This script is very similar to degree_shifts. However, I am calculating area from polygons instead of raster::area of rasters to see how accurate the calculations are.
Degree shifts
Second part of paper, if we move away from equator by 1˚ degree, how much habitat do we gain or lost
I need to look at shelf area by degrees latitude
library(raster)
library(sf)
library(ncdf4)
library(rmapshaper)
library(tidyverse)
library(diptest)
library(moments)
library(viridis) #colors
library(data.table)
library(hydroTSM) #hypsometric curves
library(gridExtra)
library(maptools)
library(rgdal)
library(rgeos)
library(SpaDES)
library(rnaturalearth)
library(rnaturalearthdata)
etopo_shelf_df <- readRDS("~/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/etopo_shelf_df.rds")
#bring in bathymetry data frame for shelf regions
#LMEs
LME_spdf <- readOGR("LME66/LMEs66.shp") #spatial points data frame with all 66 LMEs
#convert to equal area projection
#equalareaprojection<- crs(" +proj=eqearth ")
#The Lambert azimuthal equal-area projection is a particular mapping from a sphere to a disk. It accurately represents area in all regions of the sphere, but it does not accurately represent angles.
equalareaprojection<- crs(" +proj=laea ")
Make bathymetry data frame into raster (this takes a bit)
Note that I am trying to use the equal area projection
etopo_shelf_raster <- rasterFromXYZ(etopo_shelf_df, crs = crs(LME_spdf))
#reclassify all values <2000m in depth to 1 instead of actual depth
etopo_shelf_raster<- reclassify(etopo_shelf_raster,cbind(-Inf, Inf, 1))
Should go by projections of where species are moving: “Marine species (~80% being ectotherms in the database; Extended Data Fig. 2) have moved towards the poles at a mean (±s.e.m.) pace of 5.92 ± 0.94 km yr−1 (one-sample Student’s t-test: t=6.26; d.f. residuals=23; P=2.20×10–6), which is almost six times faster than terrestrial species (one-way analysis of variance (ANOVA): F=12.68; d.f. factor=1; d.f. residuals=45; P=8.88×10–4).” Lenoir 2020
5.92 km * 10 = 59.2 km in 10 years
59.2 km is how many degrees?
1° = 111 km
so,
59.2/111*1
0.5333˚ is representative of decadal shifts, but, for better visualization let’s go with 1˚ (representative of 20 year shifts)
I will put areas into 1˚ Bins (180 total degrees, so 180/1=180 total latitudinal bins)
180/1
How does continental shelf habitat change with latitude?
Look at contiguous coast lines.
I am going to leave out Antarctica (61) and the Arctic (64) as Antarctica drowned out patterns in lower latitudes and Arctic doesn’t have much habitat shallower than 2000m to begin with.
Eastern Atlantic (3) -19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 58, 59, 60, 62
Western Atlantic (2) - 5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 18, 63, 66
Eastern Pacific (1) - 1, 2, 3, 4, 11, 13, 54, 55, 65
Western Indian (4) -30, 31, 32, 33
Eastern Indian (5) -34, 38, 43, 44, 45
Western Pacific (6) 1, 35, 36, 37, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 65
Merge LMEs into 6 coastline regions
- keep in mind, LME 1 (1&6) and 54 (1&6) and 65 (1&6) appear in multiple
west_pac <- c(1, 35, 36, 37, 39, 40, 41, 42, 46, 47, 48, 49, 50, 51, 52, 53, 54, 56, 57, 65)
east_pac <- c(1, 2, 3, 4, 11, 13, 54, 55, 65)
west_atl <- c(5, 6, 7, 8, 9, 12, 14, 15, 16, 17, 18, 63, 66)
east_atl <- c(19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 58, 59, 60, 62)
west_ind <- c(30, 31, 32, 33)
east_ind <- c(34, 38, 43, 44, 45)
#subregions based on LME_number
west_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_pac,]
east_pac_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_pac,]
west_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_atl,]
west_ind_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% west_ind,]
east_atl_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_atl,]
east_ind_spdf <- LME_spdf[(LME_spdf$LME_NUMBER) %in% east_ind,]
#for subregions that span 360, we need to change CRS a bit
newCRS_west <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
west_pac_spdf_shift <- spTransform(west_pac_spdf, CRS(newCRS_west))
west_pac_spdf_shift <- gBuffer(west_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union
newCRS_east <- "+proj=longlat +datum=WGS84 +lon_wrap=180" #this shifts 180 degrees
east_pac_spdf_shift <- spTransform(east_pac_spdf, CRS(newCRS_east))
east_pac_spdf_shift <- gBuffer(east_pac_spdf_shift, byid=TRUE, width=0) #gets rid of buffers, allows for union
#rotate raster for bathymetry (guided by extent of etoposhelf raster, that's why wacky #s)
x1 <- crop(etopo_shelf_raster, extent(-180.0167, -0.0167, -90.01667, 90.01667))
x2 <- crop(etopo_shelf_raster, extent(0, 180.0167, -90.01667, 90.01667))
extent(x1) <- c(180.0167, 360.0167, -90.01667 , 90.01667)
etopo_shelf_raster_180 <- merge(x1, x2)
#get rid of buffer for east atl as well to allow for union
east_atl_spdf_nobuf <- gBuffer(east_atl_spdf, byid=TRUE, width=0)
region_names <- c("west_pac_spdf_shift", "east_pac_spdf_shift", "west_atl_spdf", "west_ind_spdf", "east_atl_spdf_nobuf", "east_ind_spdf")
#dissolve all polygons by region
for (i in 1:length(region_names)) {
name <- paste0(region_names[i], "_agg")
assign(name, gUnaryUnion(get(region_names[i]))) #dissolve polygons within coastline region into one
}
Extract bathymetry data from polygon only to make sure we’re limiting to shelf regions above 2000 meters
How to calculate area?
raster::area() Raster objects: Compute the approximate surface area of cells in an unprojected (longitude/latitude) Raster object. It is an approximation because area is computed as the height (latitudinal span) of a cell (which is constant among all cells) times the width (longitudinal span) in the (latitudinal) middle of a cell. The width is smaller at the poleward side than at the equator-ward side of a cell. This variation is greatest near the poles and the values are thus not very precise for very high latitudes. If x is a Raster* object: RasterLayer or RasterBrick. Cell values represent the size of the cell in km2, or the relative size if weights=TRUE
raster::area() SpatialPolygons: Compute the area of the spatial features. Works for both planar and angular (lon/lat) coordinate reference systems. If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
rgeos::gArea Returns the area of the geometry in the units of the current projection. By definition non-[MULTI]POLYGON geometries have an area of 0. The area of a POLYGON is the area of its shell less the area of any holes. Note that this value may be different from the area slot of the Polygons class as this value does not subtract the area of any holes in the geometry.
Now, we will split each coastline raster into latitudinal bins of 1˚
Western Pacific
north_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), 0, ymax(west_pac_spdf_shift_mask_1s))
south_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), ymin(west_pac_spdf_shift_mask_1s), 0)
#crop west_pac raster above and below 0
west_pac_spdf_shift_agg_north <- crop(west_pac_spdf_shift_mask_1s, extent(north_extent))
west_pac_spdf_shift_agg_south <- crop(west_pac_spdf_shift_mask_1s, extent(south_extent))
#unfortunately, I think I may have to just do this manually (ugly, I know)
#all chunks for west pacific
west_pac_north_latitudes <- seq(0, ymax(west_pac_spdf_shift_mask_1s), by = 1)
west_pac_south_latitudes <- seq(0, ymin(west_pac_spdf_shift_mask_1s), by = -1)
#setup data table to populate in loop, subtracting one to allow for bins
west_pac_shelf_areas <- as.data.table(matrix(nrow = (length(west_pac_north_latitudes)-1+length(west_pac_south_latitudes)-1)))
west_pac_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]
#loop for north
for (i in 1:(length(west_pac_north_latitudes)-1)) {
#setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
north_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), west_pac_north_latitudes[i], west_pac_north_latitudes[i+1])
#crop raster segement based on bin extent
segment_north <- crop(west_pac_spdf_shift_mask_1s, extent(north_extent))
#populate data table with latitudinal bin
west_pac_shelf_areas[i, "latitude_start"] <- west_pac_north_latitudes[i]
west_pac_shelf_areas[i, "latitude_end"] <- west_pac_north_latitudes[i+1]
if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
west_pac_shelf_areas[i, "area_equalareaproj"] <- 0
west_pac_shelf_areas[i, "area_rasterarea"] <- 0
west_pac_shelf_areas[i, "area_rgeos_gArea"] <- 0
print(i)
} else { #if there is shelf area within the bin, calculate area of slice
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_north)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
#populate data table with raster area
west_pac_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_north.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with polygon area using raster calculation
west_pac_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
#populate data table with polygon area using regeos calculation
west_pac_shelf_areas[i, "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
#loop for south
for (i in 1:(length(west_pac_south_latitudes)-1)) {
south_extent <- c(xmin(west_pac_spdf_shift_mask_1s), xmax(west_pac_spdf_shift_mask_1s), west_pac_south_latitudes[i+1], west_pac_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
#raster segment
segment_south <- crop(west_pac_spdf_shift_mask_1s, extent(south_extent))
#add latitude bin info to data table
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_start"] <- west_pac_south_latitudes[i]
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "latitude_end"] <- west_pac_south_latitudes[i+1]
if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- 0
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- 0
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <- 0
print(i)
} else {
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_south)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
#populate data table with raster area
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_south.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with area of polygon from raster::area function
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
#populate data table from rgeos area calculation for projected polygon
west_pac_shelf_areas[i+(length(west_pac_north_latitudes)-1), "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons
ggplot(data = west_pac_shelf_areas) +
geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
labs(x = "Latitude", y = "Area km^2") +
theme_classic()
cor(west_pac_shelf_areas[,3:5], use = "complete.obs")
save(west_pac_shelf_areas, file = "west_pac_shelf_areas.RData")
Classify by percent change!!
between 1 and Inf % change = at least 2 fold increase (note I classified any change from 0 to something as NOT a significant change, should return to this conceptually)
between -0.5 and -inf % change = at least 2 fold decrease
between -0.499 and 0.999 = no significant change
For area metric here, I used the raster::area function applied to the projected shapefile
west_pac_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
west_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
west_pac_shelf_areas_highlight <- west_pac_shelf_areas[change_above_2fold != 0,]
west_pac_shelf_areas_stats <- table(west_pac_shelf_areas[,.(change_above_2fold)])
Eastern Pacific
east_pac_spdf_shift
save(east_pac_shelf_areas, "east_pac_shelf_areas.RData")
Error in save(east_pac_shelf_areas, "east_pac_shelf_areas.RData") :
object ‘east_pac_shelf_areas.RData’ not found
east_pac_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
east_pac_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
east_pac_shelf_areas_highlight <- east_pac_shelf_areas[change_above_2fold != 0,]
east_pac_shelf_areas_stats <- table(east_pac_shelf_areas[,.(change_above_2fold)])
Western Atlantic
west_atl_spdf_mask
north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), 0, ymax(west_atl_spdf_mask_1s))
south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), ymin(west_atl_spdf_mask_1s), 0)
#crop west_atl raster above and below 0
west_atl_spdf_shift_agg_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))
west_atl_spdf_shift_agg_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))
#unfortunately, I think I may have to just do this manually (ugly, I know)
#all chunks for west atlantic
west_atl_north_latitudes <- seq(0, ymax(west_atl_spdf_mask_1s), by = 1)
west_atl_south_latitudes <- seq(0, ymin(west_atl_spdf_mask_1s), by = -1)
#setup data table to populate in loop, subtracting one to allow for bins
west_atl_shelf_areas <- as.data.table(matrix(nrow = (length(west_atl_north_latitudes)-1+length(west_atl_south_latitudes)-1)))
west_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]
#loop for north
for (i in 1:(length(west_atl_north_latitudes)-1)) {
#setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
north_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_north_latitudes[i], west_atl_north_latitudes[i+1])
#crop raster segement based on bin extent
segment_north <- crop(west_atl_spdf_mask_1s, extent(north_extent))
#populate data table with latitudinal bin
west_atl_shelf_areas[i, "latitude_start"] <- west_atl_north_latitudes[i]
west_atl_shelf_areas[i, "latitude_end"] <- west_atl_north_latitudes[i+1]
if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
west_atl_shelf_areas[i, "area_equalareaproj"] <- 0
west_atl_shelf_areas[i, "area_rasterarea"] <- 0
west_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0
print(i)
} else { #if there is shelf area within the bin, calculate area of slice
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_north)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
#populate data table with raster area
west_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_north.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with polygon area using raster calculation
west_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
#populate data table with polygon area using regeos calculation
west_atl_shelf_areas[i, "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
[1] 56
[1] 57
[1] 58
[1] 59
[1] 60
[1] 61
[1] 62
[1] 63
[1] 64
[1] 65
[1] 66
[1] 67
[1] 68
[1] 69
[1] 70
[1] 71
[1] 72
[1] 73
[1] 74
[1] 75
[1] 76
[1] 77
[1] 78
[1] 79
[1] 80
[1] 81
[1] 82
[1] 83
[1] 84
#loop for south
for (i in 1:(length(west_atl_south_latitudes)-1)) {
south_extent <- c(xmin(west_atl_spdf_mask_1s), xmax(west_atl_spdf_mask_1s), west_atl_south_latitudes[i+1], west_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
#raster segment
segment_south <- crop(west_atl_spdf_mask_1s, extent(south_extent))
#add latitude bin info to data table
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_start"] <- west_atl_south_latitudes[i]
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "latitude_end"] <- west_atl_south_latitudes[i+1]
if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- 0
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
print(i)
} else {
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_south)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
#populate data table with raster area
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_south.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with area of polygon from raster::area function
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
#populate data table from rgeos area calculation for projected polygon
west_atl_shelf_areas[i+(length(west_atl_north_latitudes)-1), "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons
ggplot(data = west_atl_shelf_areas) +
geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
labs(x = "Latitude", y = "Area km^2") +
theme_classic()

cor(west_atl_shelf_areas[,3:5], use = "complete.obs")
area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea 1.0000000 0.9999914 0.9999914
area_equalareaproj 0.9999914 1.0000000 1.0000000
area_rgeos_gArea 0.9999914 1.0000000 1.0000000
west_atl_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
west_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
west_atl_shelf_areas_highlight <- west_atl_shelf_areas[change_above_2fold != 0,]
west_atl_shelf_areas_stats <- table(west_atl_shelf_areas[,.(change_above_2fold)])
Eastern Atlantic
east_atl_spdf_nobuf_mask
north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), 0, ymax(east_atl_spdf_nobuf_mask_1s))
south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), ymin(east_atl_spdf_nobuf_mask_1s), 0)
#crop east_atl raster above and below 0
east_atl_spdf_shift_agg_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))
east_atl_spdf_shift_agg_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))
#unfortunately, I think I may have to just do this manually (ugly, I know)
#all chunks for east atlantic
east_atl_north_latitudes <- seq(0, ymax(east_atl_spdf_nobuf_mask_1s), by = 1)
east_atl_south_latitudes <- seq(0, ymin(east_atl_spdf_nobuf_mask_1s), by = -1)
#setup data table to populate in loop, subtracting one to allow for bins
east_atl_shelf_areas <- as.data.table(matrix(nrow = (length(east_atl_north_latitudes)-1+length(east_atl_south_latitudes)-1)))
east_atl_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]
#loop for north
for (i in 1:(length(east_atl_north_latitudes)-1)) {
#setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
north_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_north_latitudes[i], east_atl_north_latitudes[i+1])
#crop raster segement based on bin extent
segment_north <- crop(east_atl_spdf_nobuf_mask_1s, extent(north_extent))
#populate data table with latitudinal bin
east_atl_shelf_areas[i, "latitude_start"] <- east_atl_north_latitudes[i]
east_atl_shelf_areas[i, "latitude_end"] <- east_atl_north_latitudes[i+1]
if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
east_atl_shelf_areas[i, "area_equalareaproj"] <- 0
east_atl_shelf_areas[i, "area_rasterarea"] <- 0
east_atl_shelf_areas[i, "area_rgeos_gArea"] <- 0
print(i)
} else { #if there is shelf area within the bin, calculate area of slice
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_north)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
#populate data table with raster area
east_atl_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_north.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with polygon area using raster calculation
east_atl_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
#populate data table with polygon area using regeos calculation
east_atl_shelf_areas[i, "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40
[1] 41
[1] 42
[1] 43
[1] 44
[1] 45
[1] 46
[1] 47
[1] 48
[1] 49
[1] 50
[1] 51
[1] 52
[1] 53
[1] 54
[1] 55
[1] 56
[1] 57
[1] 58
[1] 59
[1] 60
[1] 61
[1] 62
[1] 63
[1] 64
[1] 65
[1] 66
[1] 67
[1] 68
[1] 69
[1] 70
[1] 71
[1] 72
[1] 73
[1] 74
[1] 75
[1] 76
[1] 77
[1] 78
[1] 79
[1] 80
[1] 81
[1] 82
#loop for south
for (i in 1:(length(east_atl_south_latitudes)-1)) {
south_extent <- c(xmin(east_atl_spdf_nobuf_mask_1s), xmax(east_atl_spdf_nobuf_mask_1s), east_atl_south_latitudes[i+1], east_atl_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
#raster segment
segment_south <- crop(east_atl_spdf_nobuf_mask_1s, extent(south_extent))
#add latitude bin info to data table
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_start"] <- east_atl_south_latitudes[i]
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "latitude_end"] <- east_atl_south_latitudes[i+1]
if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- 0
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- 0
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <- 0
print(i)
} else {
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_south)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
#populate data table with raster area
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_south.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with area of polygon from raster::area function
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
#populate data table from rgeos area calculation for projected polygon
east_atl_shelf_areas[i+(length(east_atl_north_latitudes)-1), "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons
ggplot(data = east_atl_shelf_areas) +
geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
labs(x = "Latitude", y = "Area km^2") +
theme_classic()

cor(east_atl_shelf_areas[,3:5], use = "complete.obs")
area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea 1.0000000 0.9999985 0.9999985
area_equalareaproj 0.9999985 1.0000000 1.0000000
area_rgeos_gArea 0.9999985 1.0000000 1.0000000
east_atl_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
east_atl_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
east_atl_shelf_areas_highlight <- east_atl_shelf_areas[change_above_2fold != 0,]
east_atl_shelf_areas_stats <- table(east_atl_shelf_areas[,.(change_above_2fold)])
Western Indian
west_ind_spdf_mask

ggplot(data = west_ind_shelf_areas) +
geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
labs(x = "Latitude", y = "Area km^2") +
theme_classic()
cor(west_ind_shelf_areas[,3:5], use = "complete.obs")
area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea 1.0000000 0.9999996 0.9999996
area_equalareaproj 0.9999996 1.0000000 1.0000000
area_rgeos_gArea 0.9999996 1.0000000 1.0000000
west_ind_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
west_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
west_ind_shelf_areas_highlight <- west_ind_shelf_areas[change_above_2fold != 0,]
west_ind_shelf_areas_stats <- table(west_ind_shelf_areas[,.(change_above_2fold)])
Eastern Indian
east_ind_spdf_mask
north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), 0, ymax(east_ind_spdf_mask_1s))
south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), ymin(east_ind_spdf_mask_1s), 0)
#crop east_ind raster above and below 0
east_ind_spdf_shift_agg_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))
east_ind_spdf_shift_agg_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))
#unfortunately, I think I may have to just do this manually (ugly, I know)
#all chunks for east indian
east_ind_north_latitudes <- seq(0, ymax(east_ind_spdf_mask_1s), by = 1)
east_ind_south_latitudes <- seq(0, ymin(east_ind_spdf_mask_1s), by = -1)
#setup data table to populate in loop, subtracting one to allow for bins
east_ind_shelf_areas <- as.data.table(matrix(nrow = (length(east_ind_north_latitudes)-1+length(east_ind_south_latitudes)-1)))
east_ind_shelf_areas[, latitude_start := as.numeric(V1)][, latitude_end := as.numeric(V1)][, area_rasterarea := as.numeric(V1)][, area_equalareaproj := as.numeric(V1)][, area_rgeos_gArea := as.numeric(V1)][, V1 := NULL]
#loop for north
for (i in 1:(length(east_ind_north_latitudes)-1)) {
#setting up extent for slicing by min and max longitudes, and i to i+1 latitudes
north_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_north_latitudes[i], east_ind_north_latitudes[i+1])
#crop raster segement based on bin extent
segment_north <- crop(east_ind_spdf_mask_1s, extent(north_extent))
#populate data table with latitudinal bin
east_ind_shelf_areas[i, "latitude_start"] <- east_ind_north_latitudes[i]
east_ind_shelf_areas[i, "latitude_end"] <- east_ind_north_latitudes[i+1]
if(all(is.na(values(segment_north)))) { #if there's no shelf area within a bin, all area = 0
east_ind_shelf_areas[i, "area_equalareaproj"] <- 0
east_ind_shelf_areas[i, "area_rasterarea"] <- 0
east_ind_shelf_areas[i, "area_rgeos_gArea"] <- 0
print(i)
} else { #if there is shelf area within the bin, calculate area of slice
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_north, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_north)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster) #in km^2
#populate data table with raster area
east_ind_shelf_areas[i, "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_north.sp <- rasterToPolygons(segment_north, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_north.sp.EA <- spTransform(segment_north.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_north.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with polygon area using raster calculation
east_ind_shelf_areas[i, "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_north.sp.EA)/1e6
#populate data table with polygon area using regeos calculation
east_ind_shelf_areas[i, "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
#loop for south
for (i in 1:(length(east_ind_south_latitudes)-1)) {
south_extent <- c(xmin(east_ind_spdf_mask_1s), xmax(east_ind_spdf_mask_1s), east_ind_south_latitudes[i+1], east_ind_south_latitudes[i]) #order= xmin, xmax, ymin, ymax)
#raster segment
segment_south <- crop(east_ind_spdf_mask_1s, extent(south_extent))
#add latitude bin info to data table
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_start"] <- east_ind_south_latitudes[i]
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "latitude_end"] <- east_ind_south_latitudes[i+1]
if(all(is.na(values(segment_south)))) { #if there's no shelf area within a bin, meaning there's no shelf area at that latitude
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- 0
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- 0
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <- 0
print(i)
} else {
#raster area calculation
#get sizes of all cells in raster [km2]
cell_size_raster<-area(segment_south, na.rm=TRUE, weights=FALSE)
#delete NAs from vector of all raster cells
cell_size_raster<-cell_size_raster[!is.na(segment_south)]
#compute area of all cells in geo_raster
#full area <- total # grid cells * median cell area (using median cares less about extreme values)
segment_area_raster <- length(cell_size_raster)*median(cell_size_raster)
#populate data table with raster area
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rasterarea"] <- segment_area_raster
#convert to spatial polygons to check area calculations
#convert segment from raster to polygon, each cell from the raster is an independent polygon, (dissolve means all cells with a value of 1 are a single polygon if connected)
segment_south.sp <- rasterToPolygons(segment_south, dissolve = T)
# If x is a SpatialPolygons* object: area of each spatial object in squared meters if the CRS is longitude/latitude, or in squared map units (typically meter)
#project to equal earth area projection
segment_south.sp.EA <- spTransform(segment_south.sp, CRSobj = equalareaprojection)
#calculate area of the spatial object in m^2
polygon_size.sp <- area(segment_south.sp.EA)
#convert from m^2 to km^2
segment_area_equalarea <- polygon_size.sp/1e6
#populate data table with area of polygon from raster::area function
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_equalareaproj"] <- segment_area_equalarea
#and then plain and simple also using rgeos::gArea
area_rgeos_gArea <- gArea(segment_south.sp.EA)/1e6
#populate data table from rgeos area calculation for projected polygon
east_ind_shelf_areas[i+(length(east_ind_north_latitudes)-1), "area_rgeos_gArea"] <- area_rgeos_gArea
print(i)
}
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13
[1] 14
[1] 15
[1] 16
[1] 17
[1] 18
[1] 19
[1] 20
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
no non-missing arguments to min; returning Infno non-missing arguments to max; returning -Inf
[1] 38
#compare raster:area calculation, to equal area still using raster::area function, to rgeos::gArea function for polygons
ggplot(data = east_ind_shelf_areas) +
geom_point(aes(x = latitude_start, y = area_rgeos_gArea), color = "purple", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_rasterarea), color = "darkgreen", size = 0.5) +
geom_point(aes(x = latitude_start, y = area_equalareaproj), color = "red", size = 0.5) +
labs(x = "Latitude", y = "Area km^2") +
theme_classic()

cor(east_ind_shelf_areas[,3:5], use = "complete.obs")
area_rasterarea area_equalareaproj area_rgeos_gArea
area_rasterarea 1.0000000 0.9999989 0.9999989
area_equalareaproj 0.9999989 1.0000000 1.0000000
area_rgeos_gArea 0.9999989 1.0000000 1.0000000
east_ind_shelf_areas[, percent_change := (area_equalareaproj-shift(area_equalareaproj, type = "lag"))/shift(area_equalareaproj, type = "lag")][,area_1000s := area_equalareaproj/1000]
east_ind_shelf_areas[, change_above_2fold := ifelse((percent_change>=1 & percent_change<Inf), 1, ifelse(percent_change<=-0.5, -1, 0))]
east_ind_shelf_areas_highlight <- east_ind_shelf_areas[change_above_2fold != 0,]
east_ind_shelf_areas_stats <- table(east_ind_shelf_areas[,.(change_above_2fold)])
Plots of latitude versus habitat availability
(area_latitude_east_ind <- ggplot() +
geom_point(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = east_ind_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
geom_rug(data = east_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
##annotate("text", x =22, y = 70000, label = "Eastern Indian Ocean") +
geom_vline(xintercept = 0) +
xlim(min(east_ind_shelf_areas$latitude_end), max(east_ind_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10)))
ggsave(area_latitude_east_ind, filename = "area_latitude_east_ind.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_west_ind <- ggplot() +
geom_point(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = west_ind_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
geom_rug(data = east_ind_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
#annotate("text", x = 30, y = 33000, label = "Western Indian Ocean") +
geom_vline(xintercept = 0) +
xlim(min(west_ind_shelf_areas$latitude_end), max(west_ind_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10))
ggsave(area_latitude_west_ind, filename = "area_latitude_west_ind.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_west_atl <- ggplot() +
geom_point(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = west_atl_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
geom_rug(data = west_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
#annotate("text", x = 80, y = 120000, label = "Western Atlantic Ocean") +
geom_vline(xintercept = 0) +
xlim(min(west_atl_shelf_areas$latitude_end), max(west_atl_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10))
ggsave(area_latitude_west_atl, filename = "area_latitude_west_atl.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_east_atl <- ggplot() +
geom_point(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = east_atl_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
geom_rug(data = east_atl_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
#annotate("text", x = 82.5, y = 110000, label = "Eastern Atlantic Ocean") +
geom_vline(xintercept = 0) +
xlim(min(east_atl_shelf_areas$latitude_end), max(east_atl_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10))
ggsave(area_latitude_east_atl, filename = "area_latitude_east_atl.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image
area_latitude_east_pac <- ggplot() +
geom_point(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = east_pac_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
geom_rug(data = east_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
#annotate("text", x = 80, y = 130000, label = "Eastern Pacific Ocean") +
geom_vline(xintercept = 0) +
xlim(min(east_pac_shelf_areas$latitude_end), max(east_pac_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10))
ggsave(area_latitude_east_pac, filename = "area_latitude_east_pac.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

(area_latitude_west_pac <- ggplot() +
geom_point(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s), shape =18) +
geom_line(data = west_pac_shelf_areas, aes(x=latitude_start, y=area_1000s)) +
#geom_point(data = west_pac_shelf_areas_highlight, aes(x = latitude_start, y = area), shape =19, color = "seagreen4", size = 2) +
geom_rug(data = west_pac_shelf_areas_highlight, aes(x = latitude_start, color = as.factor(change_above_2fold))) +
labs(x = "Latitude", y = expression(paste("Area (1000s of ", km^{2},")"))) +
scale_color_discrete(name = "Instances of 2 Fold\n Habitat Change", labels = c("Contraction", "Expansion")) +
#annotate("text", x = 90, y = 130000, label = "Western Pacific Ocean") +
geom_vline(xintercept = 0) +
xlim(min(west_pac_shelf_areas$latitude_end), max(west_pac_shelf_areas$latitude_end)) +
coord_flip() +
theme_classic() +
theme(plot.margin = margin(10, 40, 10, 10)))
ggsave(area_latitude_west_pac, filename = "area_latitude_west_pac.jpg", height = 4, units = c("in"))
Saving 7.29 x 4 in image

How many experience ‘significant’ changes in habitat (at least -50% or +200% change from one bin to another) I will go with IUCN 50% loss -> vulnerable species designation.
Bin shifts –> contractions (loss of 50%) versus expansions (gain of 200%) versus neutral
#call all objects in environment with "stats" string
stats_string<-grep("_stats",names(.GlobalEnv),value=TRUE)
stats_string_list<-do.call("list",mget(stats_string))
names(stats_string_list) <- c("Eastern Indian Ocean" ,"Western Pacific Ocean" ,"Eastern Pacific Ocean" ,"Western Atlantic Ocean" ,"Western Indian Ocean" ,"Eastern Atlantic Ocean")
significant_changes <- as.data.table(rbind(stats_string_list[[1]],stats_string_list[[2]],stats_string_list[[3]],stats_string_list[[4]],stats_string_list[[5]],stats_string_list[[6]]))
colnames(significant_changes) <- c("contraction", "neutral", "expansion")
significant_changes[, region := names(stats_string_list)][,total_bins := contraction + neutral + expansion][,contraction_percent := contraction/total_bins][,neutral_percent := neutral/total_bins][,expansion_percent := expansion/total_bins]
#melt to plot
significant_changes.long <- melt(significant_changes, id.vars = c("region"), variable.name = "change_type", measure.vars = c("contraction_percent", "neutral_percent", "expansion_percent"))
blank_theme <- theme_minimal()+
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.border = element_blank(),
panel.grid=element_blank(),
axis.ticks = element_blank(),
plot.title=element_text(size=14, face="bold")
)
ggplot(data = significant_changes.long, aes(x="", y = value, fill = change_type)) +
geom_bar(stat = "identity", width = 1) +
coord_polar("y", start=0) +
scale_fill_manual(values = c("darksalmon", "azure2", "cyan3"), name = "Habitat Change", labels = c(">= 2 Fold Contraction", "< 2 Fold Change", ">= 2 Fold Expansion")) +
facet_wrap(~region) +
geom_text(aes(label = paste0(round(value*100,1),"%")), position = position_stack(vjust = 0.1), size = 2) +
scale_x_discrete(expand = c(0,0)) +
blank_theme +
theme(axis.text.x=element_blank())
ggsave(filename = "habitatloss_gain_2fold.pdf")
Saving 7.29 x 4.51 in image

Now, I should make maps for each of these regions
Used https://gist.github.com/valentinitnelav/c7598fcfc8e53658f66feea9d3bafb40 for instructions
library(ggspatial)
world <- ne_countries(scale = "medium", returnclass = "sf")
# ~~~~~~~~~~~ Download shapefile from www.naturalearthdata.com ~~~~~~~~~~~ #
# Download countries data
download.file(url = "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip",
destfile = "ne_110m_admin_0_countries.zip")
trying URL 'http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip'
Content type 'application/zip' length 196764 bytes (192 KB)
==================================================
downloaded 192 KB
# unzip the shapefile in the directory mentioned with "exdir" argument
unzip(zipfile="ne_110m_admin_0_countries.zip", exdir = "ne_110m_admin_0_countries")
# delete the zip file
file.remove("ne_110m_admin_0_countries.zip")
[1] TRUE
# read the shapefile with readOGR from rgdal package
NE_countries <- readOGR(dsn = "ne_110m_admin_0_countries", layer = "ne_110m_admin_0_countries")
OGR data source with driver: ESRI Shapefile
Source: "/Users/zoekitchel/Documents/grad school/Rutgers/Repositories/shelf_habitat_distribution/ne_110m_admin_0_countries", layer: "ne_110m_admin_0_countries"
with 177 features
It has 94 fields
Integer64 fields read as strings: POP_EST NE_ID
class(NE_countries) # is a SpatialPolygonsDataFrame object
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Split world map by "split line" ~~~~~~~~~~~ #
# shift central/prime meridian towards west – positive values only
shift <- 180 +30
# create "split line" to split country polygons
WGS84 <- CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0")
split.line <- SpatialLines(list(Lines(list(Line(cbind(180-shift,c(-90,90)))), ID="line")),
proj4string=WGS84)
# NOTE - in case of TopologyException' errors when intersecting line with country polygons,
# apply the gBuffer solution suggested at:
# http://gis.stackexchange.com/questions/163445/r-solution-for-topologyexception-input-geom-1-is-invalid-self-intersection-er
NE_countries <- gBuffer(NE_countries, byid=TRUE, width=0)
Spatial object is not projected; GEOS expects planar coordinates
# intersecting line with country polygons
line.gInt <- gIntersection(split.line, NE_countries)
spgeom1 and spgeom2 have different proj4 strings
# create a very thin polygon (buffer) out of the intersecting "split line"
bf <- gBuffer(line.gInt, byid=TRUE, width=0.000001)
Spatial object is not projected; GEOS expects planar coordinates
# split country polygons using intersecting thin polygon (buffer)
NE_countries.split <- gDifference(NE_countries, bf, byid=TRUE)
spgeom1 and spgeom2 have different proj4 strings
# plot(NE_countries.split) # check map
class(NE_countries.split) # is a SpatialPolygons object
[1] "SpatialPolygons"
attr(,"package")
[1] "sp"
# ~~~~~~~~~~~ Create graticules ~~~~~~~~~~~ #
# create a bounding box - world extent
b.box <- as(raster::extent(-180, 180, -90, 90), "SpatialPolygons")
# assign CRS to box
proj4string(b.box) <- WGS84
# create graticules/grid lines from box
grid <- gridlines(b.box,
easts = seq(from=-180, to=180, by=20),
norths = seq(from=-90, to=90, by=10))
# create labels for graticules
grid.lbl <- labels(grid, side = 1:4)
# transform labels from SpatialPointsDataFrame to a data table that ggplot can use
grid.lbl.DT <- data.table(grid.lbl@coords, grid.lbl@data)
# prepare labels with regular expression:
# - delete unwanted labels
grid.lbl.DT[, labels := gsub(pattern="180\\*degree|90\\*degree\\*N|90\\*degree\\*S", replacement="", x=labels)]
# - replace pattern "*degree" with "°" (* needs to be escaped with \\)
grid.lbl.DT[, lbl := gsub(pattern="\\*degree", replacement="°", x=labels)]
# - delete any remaining "*"
grid.lbl.DT[, lbl := gsub(pattern="*\\*", replacement="", x=lbl)]
# adjust coordinates of labels so that they fit inside the globe
grid.lbl.DT[, long := ifelse(coords.x1 %in% c(-180,180), coords.x1*175/180, coords.x1)]
grid.lbl.DT[, lat := ifelse(coords.x2 %in% c(-90,90), coords.x2*82/90, coords.x2)]
# ~~~~~~~~~~~ Prepare data for ggplot, shift & project coordinates ~~~~~~~~~~~ #
# give the PORJ.4 string for Eckert IV projection ( changed to different projection, "+proj=eck4 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" for eckert)
PROJ <- "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
# transform graticules from SpatialLines to a data table that ggplot can use
grid.DT <- data.table(map_data(SpatialLinesDataFrame(sl=grid,
data=data.frame(1:length(grid)),
match.ID = FALSE)))
database does not (uniquely) contain the field 'name'.
# project coordinates
# assign matrix of projected coordinates as two columns in data table
grid.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]
# project coordinates of labels
grid.lbl.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]
# transform split country polygons in a data table that ggplot can use
Country.DT_shift <- data.table(map_data(as(NE_countries.split, "SpatialPolygonsDataFrame")))
database does not (uniquely) contain the field 'name'.
Country.DT <- data.table(map_data(as(NE_countries, "SpatialPolygonsDataFrame")))
# Shift coordinates
Country.DT_shift[, long.new := long + shift]
Country.DT_shift[, long.new := ifelse(long.new > 180, long.new-360, long.new)]
# project coordinates
Country.DT[, c("X","Y") := data.table(project(cbind(long, lat), proj=PROJ))]
Country.DT_shift[, c("X","Y") := data.table(project(cbind(long.new, lat), proj=PROJ))]
# ~~~~~~~~~~~ Plot map ~~~~~~~~~~~ #
ggplot() +
# add projected countries
geom_polygon(data = Country.DT_shift,
aes(x = long.new+150, y = lat, group = group),
colour = "gray70",
fill = "gray90",
size = 0.25) +
# add graticules
geom_path(data = grid.DT,
aes(x = X, y = Y, group = group),
linetype = "dotted", colour = "grey50", size = .25) +
# add a bounding box (select graticules at edges)
geom_path(data = grid.DT[(long %in% c(-180,180) & region == "NS")
|(long %in% c(-180,180) & lat %in% c(-90,90) & region == "EW")],
aes(x = X, y = Y, group = group),
linetype = "solid", colour = "black", size = .3) +
# add graticule labels
geom_text(data = grid.lbl.DT, # latitude
aes(x = X, y = Y, label = lbl),
colour = "grey50", size = 2) +
# ensures that one unit on the x-axis is the same length as one unit on the y-axis
coord_equal() + # same as coord_fixed(ratio = 1)
# set empty theme
theme_void()

region_maps <- list()
regions_shift_projection <- c("west_pac_spdf_shift", "east_pac_spdf_shift")
for (i in 1:length(region_names)) {
region_spdf <- get(paste0(region_names[i], "_mask"))
if(region_names[i] %in% regions_shift_projection) {
#pacific centered projection
region_spdf_mask_1s_extent <- extent(get(paste0(region_names[i],"_mask_1s"))) # take extent of region
#convert rasters to dfs data frame
region_spdf <- as(get(paste0(region_names[i],"_mask_1s")), "SpatialPixelsDataFrame")
region_df <- as.data.frame(region_spdf)
colnames(region_df) <- c("value", "x", "y")
(region_maps[[i]] <- ggplot() +
# add projected countries
geom_polygon(data = Country.DT_shift,
aes(x = long.new+150, y = lat, group = group),
colour = "gray70",
fill = "gray90",
size = 0.25) +
geom_tile(data = region_df, aes(x = x, y = y, fill = value), color = "seagreen4") +
coord_sf(x = c(region_spdf_mask_1s_extent[1], region_spdf_mask_1s_extent[2]), y = c(region_spdf_mask_1s_extent[3], region_spdf_mask_1s_extent[4])) +
labs( x = expression("Longitude ("*~degree*E*")"), y = expression("Latitude ("*~degree*N*")")) +
geom_abline(intercept = 0, slope = 0) +
theme_classic() +
theme(legend.position = "none"))
filename <- paste0(region_names[i], "_map.jpg")
ggsave(plot = region_maps[[i]], filename = filename, height = 4, units = c("in"))
} else {
#atlantic centered projection
region_spdf_mask_1s_extent <- extent(get(paste0(region_names[i],"_mask_1s"))) # take extent of region
#convert rasters to dfs data frame
region_spdf <- as(get(paste0(region_names[i],"_mask_1s")), "SpatialPixelsDataFrame")
region_df <- as.data.frame(region_spdf)
colnames(region_df) <- c("value", "x", "y")
(region_maps[[i]] <- ggplot() +
# add projected countries
geom_polygon(data = Country.DT,
aes(x = long, y = lat, group = group),
colour = "gray70",
fill = "gray90",
size = 0.25) +
geom_tile(data = region_df, aes(x = x, y = y, fill = value), color = "seagreen4") +
coord_sf(x = c(region_spdf_mask_1s_extent[1], region_spdf_mask_1s_extent[2]), y = c(region_spdf_mask_1s_extent[3], region_spdf_mask_1s_extent[4])) +
labs( x = expression("Longitude ("*~degree*E*")"), y = expression("Latitude ("*~degree*N*")")) +
geom_abline(intercept = 0, slope = 0) +
theme_classic() +
theme(legend.position = "none"))
filename <- paste0(region_names[i], "_map.jpg")
ggsave(plot = region_maps[[i]], filename = filename, height = 4, units = c("in"))
}
}
Saving 7 x 4 in image
Combining plots
region_maps: “west_pac_spdf_shift”, “east_pac_spdf_shift”, “west_atl_spdf”, “west_ind_spdf”, “east_atl_spdf_nobuf”, “east_ind_spdf”
Plots of area versus latitude area_latitude_east_pac
Now, combine plots
library(egg)
library(ggpubr)
#west pacific
(west_pacific_merge_map_plot <- egg::ggarrange(region_maps[[1]],
area_latitude_west_pac
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ),
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.



ggsave(plot = west_pacific_merge_map_plot, filename = "west_pacific_merge_map_plot.jpg", width = 7, height = 3, units = "in")
#east pacific
(east_pacific_merge_map_plot <- egg::ggarrange(region_maps[[2]],
area_latitude_east_pac
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )
,
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.


ggsave(plot = east_pacific_merge_map_plot, filename = "east_pacific_merge_map_plot.jpg", width = 7, height = 3, units = "in")
#west atlantic
(west_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[3]],
area_latitude_west_atl
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )
,
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.


ggsave(plot = west_atlantic_merge_map_plot, filename = "west_atlantic_merge_map_plot.jpg", width = 7, height = 3, units = "in")
#west indian
(west_indian_merge_map_plot <- egg::ggarrange(region_maps[[4]],
area_latitude_west_ind
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )
,
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.


ggsave(plot = west_indian_merge_map_plot, filename = "west_indian_merge_map_plot.jpg", width = 7, height = 3, units = "in")
#east atlantic
(east_atlantic_merge_map_plot <- egg::ggarrange(region_maps[[5]],
area_latitude_east_atl
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )
,
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.


ggsave(plot = east_atlantic_merge_map_plot, filename = "east_atlantic_merge_map_plot.jpg", width = 7, height = 3, units = "in")
#east indian
(east_indian_merge_map_plot <- egg::ggarrange(region_maps[[6]],
area_latitude_east_ind
+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() )
,
nrow = 1,
top = T))
range backtransformation not implemented in this coord; results may be wrong.


ggsave(plot = east_indian_merge_map_plot, filename = "east_indian_merge_map_plot.jpg", width = 7, height = 3, units = "in")
Make map of world
Each region coded with # expansions and # contractions
save(significant_changes.long, significant_changes, file = "significant_changes.RData")
LS0tCnRpdGxlOiAiRGVncmVlIHNoaWZ0cyBidXQgcHJvamVjdGVkIHRvIGNhbGN1bGF0ZSBBcmVhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIHNjcmlwdCBpcyB2ZXJ5IHNpbWlsYXIgdG8gZGVncmVlX3NoaWZ0cy4gSG93ZXZlciwgSSBhbSBjYWxjdWxhdGluZyBhcmVhIGZyb20gcG9seWdvbnMgaW5zdGVhZCBvZiByYXN0ZXI6OmFyZWEgb2YgcmFzdGVycyB0byBzZWUgaG93IGFjY3VyYXRlIHRoZSBjYWxjdWxhdGlvbnMgYXJlLiAKCgpEZWdyZWUgc2hpZnRzCgpTZWNvbmQgcGFydCBvZiBwYXBlciwgaWYgd2UgbW92ZSBhd2F5IGZyb20gZXF1YXRvciBieSAxy5ogZGVncmVlLCBob3cgbXVjaCBoYWJpdGF0IGRvIHdlIGdhaW4gb3IgbG9zdAoKSSBuZWVkIHRvIGxvb2sgYXQgc2hlbGYgYXJlYSBieSBkZWdyZWVzIGxhdGl0dWRlCgpgYGB7ciBzZXR1cH0KbGlicmFyeShyYXN0ZXIpCmxpYnJhcnkoc2YpCmxpYnJhcnkobmNkZjQpCmxpYnJhcnkocm1hcHNoYXBlcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZGlwdGVzdCkKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KHZpcmlkaXMpICNjb2xvcnMKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGh5ZHJvVFNNKSAjaHlwc29tZXRyaWMgY3VydmVzCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KG1hcHRvb2xzKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KHJnZW9zKQpsaWJyYXJ5KFNwYURFUykKbGlicmFyeShybmF0dXJhbGVhcnRoKQpsaWJyYXJ5KHJuYXR1cmFsZWFydGhkYXRhKQoKCmV0b3BvX3NoZWxmX2RmIDwtIHJlYWRSRFMoIn4vRG9jdW1lbnRzL2dyYWQgc2Nob29sL1J1dGdlcnMvUmVwb3NpdG9yaWVzL3NoZWxmX2hhYml0YXRfZGlzdHJpYnV0aW9uL2V0b3BvX3NoZWxmX2RmLnJkcyIpCiNicmluZyBpbiBiYXRoeW1ldHJ5IGRhdGEgZnJhbWUgZm9yIHNoZWxmIHJlZ2lvbnMKCiNMTUVzCkxNRV9zcGRmIDwtIHJlYWRPR1IoIkxNRTY2L0xNRXM2Ni5zaHAiKSAjc3BhdGlhbCBwb2ludHMgZGF0YSBmcmFtZSB3aXRoIGFsbCA2NiBMTUVzCgoKI2NvbnZlcnQgdG8gZXF1YWwgYXJlYSBwcm9qZWN0aW9uCiNlcXVhbGFyZWFwcm9qZWN0aW9uPC0gY3JzKCIgK3Byb2o9ZXFlYXJ0aCAiKQoKI1RoZSBMYW1iZXJ0IGF6aW11dGhhbCBlcXVhbC1hcmVhIHByb2plY3Rpb24gaXMgYSBwYXJ0aWN1bGFyIG1hcHBpbmcgZnJvbSBhIHNwaGVyZSB0byBhIGRpc2suIEl0IGFjY3VyYXRlbHkgcmVwcmVzZW50cyBhcmVhIGluIGFsbCByZWdpb25zIG9mIHRoZSBzcGhlcmUsIGJ1dCBpdCBkb2VzIG5vdCBhY2N1cmF0ZWx5IHJlcHJlc2VudCBhbmdsZXMuCmVxdWFsYXJlYXByb2plY3Rpb248LSBjcnMoIiArcHJvaj1sYWVhICIpCgoKCgpgYGAKCk1ha2UgYmF0aHltZXRyeSBkYXRhIGZyYW1lIGludG8gcmFzdGVyICh0aGlzIHRha2VzIGEgYml0KQoKTm90ZSB0aGF0IEkgYW0gdHJ5aW5nIHRvIHVzZSB0aGUgW2VxdWFsIGFyZWEgcHJvamVjdGlvbl0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vMjAxOC8wOS9xdWljay1oaXQtdXNpbmctdGhlLW5ldy1lcXVhbC1lYXJ0aC1wcm9qZWN0aW9uLWluLXIvKQpgYGB7ciBiYXRoeSB0byByYXN0ZXJ9CgpldG9wb19zaGVsZl9yYXN0ZXIgPC0gcmFzdGVyRnJvbVhZWihldG9wb19zaGVsZl9kZiwgY3JzID0gY3JzKExNRV9zcGRmKSkKCiNyZWNsYXNzaWZ5IGFsbCB2YWx1ZXMgPDIwMDBtIGluIGRlcHRoIHRvIDEgaW5zdGVhZCBvZiBhY3R1YWwgZGVwdGgKZXRvcG9fc2hlbGZfcmFzdGVyPC0gcmVjbGFzc2lmeShldG9wb19zaGVsZl9yYXN0ZXIsY2JpbmQoLUluZiwgSW5mLCAxKSkKCmBgYAoKClNob3VsZCBnbyBieSBwcm9qZWN0aW9ucyBvZiB3aGVyZSBzcGVjaWVzIGFyZSBtb3Zpbmc6CiJNYXJpbmUgc3BlY2llcyAofjgwJSBiZWluZyBlY3RvdGhlcm1zIGluIHRoZSBkYXRhYmFzZTsgRXh0ZW5kZWQgRGF0YSBGaWcuIDIpIGhhdmUgbW92ZWQgdG93YXJkcyB0aGUgcG9sZXMgYXQgYSBtZWFuICjCsXMuZS5tLikgcGFjZSBvZiA1LjkyIMKxIDAuOTQga20geXLiiJIxIChvbmUtc2FtcGxlIFN0dWRlbnTigJlzIHQtdGVzdDogdD02LjI2OyBkLmYuIHJlc2lkdWFscz0yMzsgUD0yLjIww5cxMOKAkzYpLCB3aGljaCBpcyBhbG1vc3Qgc2l4IHRpbWVzIGZhc3RlciB0aGFuIHRlcnJlc3RyaWFsIHNwZWNpZXMgKG9uZS13YXkgYW5hbHlzaXMgb2YgdmFyaWFuY2UgKEFOT1ZBKTogRj0xMi42ODsgZC5mLiBmYWN0b3I9MTsgZC5mLiByZXNpZHVhbHM9NDU7IFA9OC44OMOXMTDigJM0KS4iIExlbm9pciAyMDIwCgo1LjkyIGttICogMTAgPSA1OS4yIGttIGluIDEwIHllYXJzCgo1OS4yIGttIGlzIGhvdyBtYW55IGRlZ3JlZXM/CgoxwrAgPSAxMTEga20KCnNvLCAKCmBgYHtyIHF1aWNrIGNvbnZlcnNpb259CjU5LjIvMTExKjEKCmBgYAoKMC41MzMzy5ogaXMgcmVwcmVzZW50YXRpdmUgb2YgZGVjYWRhbCBzaGlmdHMsIGJ1dCwgZm9yIGJldHRlciB2aXN1YWxpemF0aW9uIGxldCdzIGdvIHdpdGggMcuaIChyZXByZXNlbnRhdGl2ZSBvZiAyMCB5ZWFyIHNoaWZ0cykKCkkgd2lsbCBwdXQgYXJlYXMgaW50byAxy5ogQmlucyAoMTgwIHRvdGFsIGRlZ3JlZXMsIHNvIDE4MC8xPTE4MCB0b3RhbCBsYXRpdHVkaW5hbCBiaW5zKQoKYGBge3J9CjE4MC8xCmBgYAoKSG93IGRvZXMgY29udGluZW50YWwgc2hlbGYgaGFiaXRhdCBjaGFuZ2Ugd2l0aCBsYXRpdHVkZT8KCkxvb2sgYXQgY29udGlndW91cyBjb2FzdCBsaW5lcy4KCkkgYW0gZ29pbmcgdG8gbGVhdmUgb3V0IEFudGFyY3RpY2EgKDYxKSBhbmQgdGhlIEFyY3RpYyAoNjQpIGFzIEFudGFyY3RpY2EgZHJvd25lZCBvdXQgcGF0dGVybnMgaW4gbG93ZXIgbGF0aXR1ZGVzIGFuZCBBcmN0aWMgZG9lc24ndCBoYXZlIG11Y2ggaGFiaXRhdCBzaGFsbG93ZXIgdGhhbiAyMDAwbSB0byBiZWdpbiB3aXRoLiAKCkVhc3Rlcm4gQXRsYW50aWMgKDMpCi0xOSwgMjAsIDIxLCAyMiwgMjMsIDI0LCAyNSwgMjYsIDI3LCAyOCwgMjksIDU4LCA1OSwgNjAsIDYyCgpXZXN0ZXJuIEF0bGFudGljICgyKQotIDUsIDYsIDcsIDgsIDksIDEyLCAxNCwgMTUsIDE2LCAxNywgMTgsIDYzLCA2NgoKRWFzdGVybiBQYWNpZmljICgxKQotIDEsIDIsIDMsIDQsIDExLCAxMywgNTQsIDU1LCA2NQoKV2VzdGVybiBJbmRpYW4gKDQpCi0zMCwgMzEsIDMyLCAzMwoKRWFzdGVybiBJbmRpYW4gKDUpCi0zNCwgMzgsIDQzLCA0NCwgNDUKCldlc3Rlcm4gUGFjaWZpYyAoNikKMSwJMzUsCTM2LAkzNywJMzksCTQwLAk0MSwJNDIsCTQ2LAk0NywJNDgsCTQ5LAk1MCwJNTEsCTUyLAk1MywJNTQsCTU2LAk1NywJNjUKCk1lcmdlIExNRXMgaW50byA2IGNvYXN0bGluZSByZWdpb25zCgotIGtlZXAgaW4gbWluZCwgTE1FIDEgKDEmNikgYW5kIDU0ICgxJjYpIGFuZCA2NSAoMSY2KSBhcHBlYXIgaW4gbXVsdGlwbGUKYGBge3IgbWVyZ2luZyBMTUVzfQp3ZXN0X3BhYyA8LSBjKDEsCTM1LAkzNiwJMzcsCTM5LAk0MCwJNDEsCTQyLAk0NiwJNDcsCTQ4LAk0OSwJNTAsCTUxLAk1MiwJNTMsCTU0LAk1NiwJNTcsCTY1KQplYXN0X3BhYyA8LSBjKDEsIDIsIDMsIDQsIDExLCAxMywgNTQsIDU1LCA2NSkKd2VzdF9hdGwgPC0gYyg1LCA2LCA3LCA4LCA5LCAxMiwgMTQsIDE1LCAxNiwgMTcsIDE4LCA2MywgNjYpCmVhc3RfYXRsIDwtIGMoMTksIDIwLCAyMSwgMjIsIDIzLCAyNCwgMjUsIDI2LCAyNywgMjgsIDI5LCA1OCwgNTksIDYwLCA2MikKd2VzdF9pbmQgPC0gYygzMCwgMzEsIDMyLCAzMykKZWFzdF9pbmQgPC0gYygzNCwgMzgsIDQzLCA0NCwgNDUpCgojc3VicmVnaW9ucyBiYXNlZCBvbiBMTUVfbnVtYmVyCndlc3RfcGFjX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgd2VzdF9wYWMsXQplYXN0X3BhY19zcGRmIDwtIExNRV9zcGRmWyhMTUVfc3BkZiRMTUVfTlVNQkVSKSAlaW4lIGVhc3RfcGFjLF0Kd2VzdF9hdGxfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSB3ZXN0X2F0bCxdCndlc3RfaW5kX3NwZGYgPC0gTE1FX3NwZGZbKExNRV9zcGRmJExNRV9OVU1CRVIpICVpbiUgd2VzdF9pbmQsXQplYXN0X2F0bF9zcGRmIDwtIExNRV9zcGRmWyhMTUVfc3BkZiRMTUVfTlVNQkVSKSAlaW4lIGVhc3RfYXRsLF0KZWFzdF9pbmRfc3BkZiA8LSBMTUVfc3BkZlsoTE1FX3NwZGYkTE1FX05VTUJFUikgJWluJSBlYXN0X2luZCxdCgojZm9yIHN1YnJlZ2lvbnMgdGhhdCBzcGFuIDM2MCwgd2UgbmVlZCB0byBjaGFuZ2UgQ1JTIGEgYml0Cm5ld0NSU193ZXN0IDwtICIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCArbG9uX3dyYXA9MTgwIiAjdGhpcyBzaGlmdHMgMTgwIGRlZ3JlZXMKd2VzdF9wYWNfc3BkZl9zaGlmdCA8LSBzcFRyYW5zZm9ybSh3ZXN0X3BhY19zcGRmLCBDUlMobmV3Q1JTX3dlc3QpKQp3ZXN0X3BhY19zcGRmX3NoaWZ0IDwtIGdCdWZmZXIod2VzdF9wYWNfc3BkZl9zaGlmdCwgYnlpZD1UUlVFLCB3aWR0aD0wKSAjZ2V0cyByaWQgb2YgYnVmZmVycywgYWxsb3dzIGZvciB1bmlvbgoKbmV3Q1JTX2Vhc3QgPC0gIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0ICtsb25fd3JhcD0xODAiICN0aGlzIHNoaWZ0cyAxODAgZGVncmVlcwplYXN0X3BhY19zcGRmX3NoaWZ0IDwtIHNwVHJhbnNmb3JtKGVhc3RfcGFjX3NwZGYsIENSUyhuZXdDUlNfZWFzdCkpCmVhc3RfcGFjX3NwZGZfc2hpZnQgPC0gZ0J1ZmZlcihlYXN0X3BhY19zcGRmX3NoaWZ0LCBieWlkPVRSVUUsIHdpZHRoPTApICNnZXRzIHJpZCBvZiBidWZmZXJzLCBhbGxvd3MgZm9yIHVuaW9uCgojcm90YXRlIHJhc3RlciBmb3IgYmF0aHltZXRyeSAoZ3VpZGVkIGJ5IGV4dGVudCBvZiBldG9wb3NoZWxmIHJhc3RlciwgIHRoYXQncyB3aHkgd2Fja3kgI3MpCngxIDwtIGNyb3AoZXRvcG9fc2hlbGZfcmFzdGVyLCBleHRlbnQoLTE4MC4wMTY3LCAtMC4wMTY3LCAtOTAuMDE2NjcsIDkwLjAxNjY3KSkKeDIgPC0gY3JvcChldG9wb19zaGVsZl9yYXN0ZXIsIGV4dGVudCgwLCAxODAuMDE2NywgLTkwLjAxNjY3LCA5MC4wMTY2NykpICAgCmV4dGVudCh4MSkgPC0gYygxODAuMDE2NywgMzYwLjAxNjcsIC05MC4wMTY2NyAsIDkwLjAxNjY3KQpldG9wb19zaGVsZl9yYXN0ZXJfMTgwIDwtIG1lcmdlKHgxLCB4MikKCiNnZXQgcmlkIG9mIGJ1ZmZlciBmb3IgZWFzdCBhdGwgYXMgd2VsbCB0byBhbGxvdyBmb3IgdW5pb24KCmVhc3RfYXRsX3NwZGZfbm9idWYgPC0gZ0J1ZmZlcihlYXN0X2F0bF9zcGRmLCBieWlkPVRSVUUsIHdpZHRoPTApCgpyZWdpb25fbmFtZXMgPC0gYygid2VzdF9wYWNfc3BkZl9zaGlmdCIsICJlYXN0X3BhY19zcGRmX3NoaWZ0IiwgIndlc3RfYXRsX3NwZGYiLCAid2VzdF9pbmRfc3BkZiIsICJlYXN0X2F0bF9zcGRmX25vYnVmIiwgImVhc3RfaW5kX3NwZGYiKQoKCgojZGlzc29sdmUgYWxsIHBvbHlnb25zIGJ5IHJlZ2lvbgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzKSkgewogIG5hbWUgPC0gcGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwgIl9hZ2ciKQogIGFzc2lnbihuYW1lLCBnVW5hcnlVbmlvbihnZXQocmVnaW9uX25hbWVzW2ldKSkpICNkaXNzb2x2ZSBwb2x5Z29ucyB3aXRoaW4gY29hc3RsaW5lIHJlZ2lvbiBpbnRvIG9uZQp9CgpgYGAKCgpFeHRyYWN0IGJhdGh5bWV0cnkgZGF0YSBmcm9tIHBvbHlnb24gb25seSB0byBtYWtlIHN1cmUgd2UncmUgbGltaXRpbmcgdG8gc2hlbGYgcmVnaW9ucyBhYm92ZSAyMDAwIG1ldGVycwoKYGBge3IgcG9seWdvbiB0byByYXN0ZXJ9CgpyZWdpb25fbmFtZXNfc2hpZnQgPC0gcmVnaW9uX25hbWVzWzE6Ml0KCgpyZWdpb25fbmFtZXNfbm9zaGlmdCA8LSByZWdpb25fbmFtZXNbMzo2XQoKCmZvciAoaSBpbiAxOmxlbmd0aChyZWdpb25fbmFtZXNfbm9zaGlmdCkpIHsKI2Nyb3AgYmF0aHltZXRyeSBsYXllciB0byBMTUUgc3Vic2V0IChjb250aW5lbnRhbCBzaGVsZiBoYWJpdGF0IGluIExNRXMpCiAgcmFzdGVyX2V4dGVudCA8LQogICAgICAgY3JvcChldG9wb19zaGVsZl9yYXN0ZXIsIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX2FnZyIpKSkpCgojd2hpY2ggYXJlYXMgb2YgcmFzdGVyIGZhbGwgd2l0aGluIGJvcmRlcnM/CiAgYXNzaWduKHBhc3RlMChyZWdpb25fbmFtZXNfbm9zaGlmdFtpXSwgIl9tYXNrIiksCiAgICAgICBtYXNrKHJhc3Rlcl9leHRlbnQsIGdldChwYXN0ZTAocmVnaW9uX25hbWVzX25vc2hpZnRbaV0sICJfYWdnIikpKSkKICAKICAgIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX25vc2hpZnRbaV0sICJfbWFza18xcyIpLAogICAgICAgcmVjbGFzc2lmeShnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19ub3NoaWZ0W2ldLCAiX21hc2siKSksIGNiaW5kKC1JbmYsIEluZiwgMSkpKQoKICAKCn0KCiNlZGl0IGZvciBlYXN0X3BhY19zcGRmX3NoaWZ0IGFuZCB3ZXN0X3BhY19zcGRmX3NoaWZ0ICgrMTgwy5opCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzX3NoaWZ0WzE6Ml0pKSB7CiNjcm9wIGJhdGh5IGxheWVyIHRvIExNRSBzdWJzZXQKICByYXN0ZXJfZXh0ZW50IDwtCiAgICAgICBjcm9wKGV0b3BvX3NoZWxmX3Jhc3Rlcl8xODAsIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc19zaGlmdFtpXSwgIl9hZ2ciKSkpKQoKI3doaWNoIGFyZWFzIG9mIHJhc3RlciBmYWxsIHdpdGhpbiBib3JkZXJzPwogIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX21hc2siKSwKICAgICAgIG1hc2socmFzdGVyX2V4dGVudCwgZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfc2hpZnRbaV0sICJfYWdnIikpKSkKICAKICAgIGFzc2lnbihwYXN0ZTAocmVnaW9uX25hbWVzX3NoaWZ0W2ldLCAiX21hc2tfMXMiKSwKICAgICAgIHJlY2xhc3NpZnkoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNfc2hpZnRbaV0sICJfbWFzayIpKSwgY2JpbmQoLUluZiwgSW5mLCAxKSkpCgp9CgpgYGAKCgpIb3cgdG8gY2FsY3VsYXRlIGFyZWE/CgotIHJhc3Rlcjo6YXJlYSgpClJhc3RlciBvYmplY3RzOiBDb21wdXRlIHRoZSBhcHByb3hpbWF0ZSBzdXJmYWNlIGFyZWEgb2YgY2VsbHMgaW4gYW4gdW5wcm9qZWN0ZWQgKGxvbmdpdHVkZS9sYXRpdHVkZSkgUmFzdGVyIG9iamVjdC4gSXQgaXMgYW4gYXBwcm94aW1hdGlvbiBiZWNhdXNlIGFyZWEgaXMgY29tcHV0ZWQgYXMgdGhlIGhlaWdodCAobGF0aXR1ZGluYWwgc3Bhbikgb2YgYSBjZWxsICh3aGljaCBpcyBjb25zdGFudCBhbW9uZyBhbGwgY2VsbHMpIHRpbWVzIHRoZSB3aWR0aCAobG9uZ2l0dWRpbmFsIHNwYW4pIGluIHRoZSAobGF0aXR1ZGluYWwpIG1pZGRsZSBvZiBhIGNlbGwuIFRoZSB3aWR0aCBpcyBzbWFsbGVyIGF0IHRoZSBwb2xld2FyZCBzaWRlIHRoYW4gYXQgdGhlIGVxdWF0b3Itd2FyZCBzaWRlIG9mIGEgY2VsbC4gVGhpcyB2YXJpYXRpb24gaXMgZ3JlYXRlc3QgbmVhciB0aGUgcG9sZXMgYW5kIHRoZSB2YWx1ZXMgYXJlIHRodXMgbm90IHZlcnkgcHJlY2lzZSBmb3IgdmVyeSBoaWdoIGxhdGl0dWRlcy4gSWYgeCBpcyBhIFJhc3Rlciogb2JqZWN0OiBSYXN0ZXJMYXllciBvciBSYXN0ZXJCcmljay4gQ2VsbCB2YWx1ZXMgcmVwcmVzZW50IHRoZSBzaXplIG9mIHRoZSBjZWxsIGluIGttMiwgb3IgdGhlIHJlbGF0aXZlIHNpemUgaWYgd2VpZ2h0cz1UUlVFCgoKCi0gcmFzdGVyOjphcmVhKCkgClNwYXRpYWxQb2x5Z29uczogQ29tcHV0ZSB0aGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBmZWF0dXJlcy4gV29ya3MgZm9yIGJvdGggcGxhbmFyIGFuZCBhbmd1bGFyIChsb24vbGF0KSBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1zLiBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKCi0gcmdlb3M6OmdBcmVhClJldHVybnMgdGhlIGFyZWEgb2YgdGhlIGdlb21ldHJ5IGluIHRoZSB1bml0cyBvZiB0aGUgY3VycmVudCBwcm9qZWN0aW9uLiBCeSBkZWZpbml0aW9uIG5vbi1bTVVMVEldUE9MWUdPTiBnZW9tZXRyaWVzIGhhdmUgYW4gYXJlYSBvZiAwLiBUaGUgYXJlYSBvZiBhIFBPTFlHT04gaXMgdGhlIGFyZWEgb2YgaXRzIHNoZWxsIGxlc3MgdGhlIGFyZWEgb2YgYW55IGhvbGVzLiBOb3RlIHRoYXQgdGhpcyB2YWx1ZSBtYXkgYmUgZGlmZmVyZW50IGZyb20gdGhlIGFyZWEgc2xvdCBvZiB0aGUgUG9seWdvbnMgY2xhc3MgYXMgdGhpcyB2YWx1ZSBkb2VzIG5vdCBzdWJ0cmFjdCB0aGUgYXJlYSBvZiBhbnkgaG9sZXMgaW4gdGhlIGdlb21ldHJ5LgoKCk5vdywgd2Ugd2lsbCBzcGxpdCBlYWNoIGNvYXN0bGluZSByYXN0ZXIgaW50byBsYXRpdHVkaW5hbCBiaW5zIG9mIDHLmgoKV2VzdGVybiBQYWNpZmljCmBgYHtyIHNwbGl0IHJhc3RlciBmb3Igd2VzdGVybiBwYWNpZmljfQpub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgMCwgeW1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpKQpzb3V0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHhtYXgod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeW1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCAwKQoKI2Nyb3Agd2VzdF9wYWMgcmFzdGVyIGFib3ZlIGFuZCBiZWxvdyAwCndlc3RfcGFjX3NwZGZfc2hpZnRfYWdnX25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKCndlc3RfcGFjX3NwZGZfc2hpZnRfYWdnX3NvdXRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKCiN1bmZvcnR1bmF0ZWx5LCBJIHRoaW5rIEkgbWF5IGhhdmUgdG8ganVzdCBkbyB0aGlzIG1hbnVhbGx5ICh1Z2x5LCBJIGtub3cpCgojYWxsIGNodW5rcyBmb3Igd2VzdCBwYWNpZmljCndlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IDEpCndlc3RfcGFjX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfcGFjX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfcGFjX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCB4bWF4KHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcyksIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9wYWNfc3BkZl9zaGlmdF9tYXNrXzFzKSwgeG1heCh3ZXN0X3BhY19zcGRmX3NoaWZ0X21hc2tfMXMpLCB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfcGFjX3NwZGZfc2hpZnRfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9wYWNfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQogICAgCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7CiAgCiAgICAjcmFzdGVyIGFyZWEgY2FsY3VsYXRpb24KICAgICAgI2dldCBzaXplcyBvZiBhbGwgY2VsbHMgaW4gcmFzdGVyIFtrbTJdCiAgICBjZWxsX3NpemVfcmFzdGVyPC1hcmVhKHNlZ21lbnRfc291dGgsIG5hLnJtPVRSVUUsIHdlaWdodHM9RkFMU0UpCiAgICAKICAgICNkZWxldGUgTkFzIGZyb20gdmVjdG9yIG9mIGFsbCByYXN0ZXIgY2VsbHMKICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWNlbGxfc2l6ZV9yYXN0ZXJbIWlzLm5hKHNlZ21lbnRfc291dGgpXQogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICB3ZXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X3NvdXRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9zb3V0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9zb3V0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X3NvdXRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGFyZWEgb2YgcG9seWdvbiBmcm9tIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbgogIHdlc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSBmcm9tIHJnZW9zIGFyZWEgY2FsY3VsYXRpb24gZm9yIHByb2plY3RlZCBwb2x5Z29uCiAgd2VzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojY29tcGFyZSByYXN0ZXI6YXJlYSBjYWxjdWxhdGlvbiwgdG8gZXF1YWwgYXJlYSBzdGlsbCB1c2luZyByYXN0ZXI6OmFyZWEgZnVuY3Rpb24sIHRvIHJnZW9zOjpnQXJlYSBmdW5jdGlvbiBmb3IgcG9seWdvbnMKCmdncGxvdChkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXMpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3JnZW9zX2dBcmVhKSwgY29sb3IgPSAicHVycGxlIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmFzdGVyYXJlYSksIGNvbG9yID0gImRhcmtncmVlbiIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX2VxdWFsYXJlYXByb2opLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMC41KSArCiAgbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9ICJBcmVhIGttXjIiKSArCiAgdGhlbWVfY2xhc3NpYygpCgpjb3Iod2VzdF9wYWNfc2hlbGZfYXJlYXNbLDM6NV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKc2F2ZSh3ZXN0X3BhY19zaGVsZl9hcmVhcywgZmlsZSA9ICJ3ZXN0X3BhY19zaGVsZl9hcmVhcy5SRGF0YSIpCgpgYGAKCkNsYXNzaWZ5IGJ5IHBlcmNlbnQgY2hhbmdlISEKCmJldHdlZW4gMSBhbmQgSW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGluY3JlYXNlIChub3RlIEkgY2xhc3NpZmllZCBhbnkgY2hhbmdlIGZyb20gMCB0byBzb21ldGhpbmcgYXMgTk9UIGEgc2lnbmlmaWNhbnQgY2hhbmdlLCBzaG91bGQgcmV0dXJuIHRvIHRoaXMgY29uY2VwdHVhbGx5KQoKYmV0d2VlbiAtMC41IGFuZCAtaW5mICUgY2hhbmdlID0gYXQgbGVhc3QgMiBmb2xkIGRlY3JlYXNlCgpiZXR3ZWVuIC0wLjQ5OSBhbmQgMC45OTkgPSBubyBzaWduaWZpY2FudCBjaGFuZ2UgCgpGb3IgYXJlYSBtZXRyaWMgaGVyZSwgSSB1c2VkIHRoZSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24gYXBwbGllZCB0byB0aGUgcHJvamVjdGVkIHNoYXBlZmlsZQpgYGB7ciBwZXJjZW50IHNoaWZ0IHdlc3Rlcm4gcGFjaWZpY30Kd2VzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfcGFjX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9wYWNfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9wYWNfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKCkVhc3Rlcm4gUGFjaWZpYwoKZWFzdF9wYWNfc3BkZl9zaGlmdAoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciBlYXN0ZXJuIHBhY2lmaWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCAwLCB5bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB5bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIDApCgojY3JvcCBlYXN0X3BhYyByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKZWFzdF9wYWNfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKZWFzdF9wYWNfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciBlYXN0IHBhY2lmaWMKZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gMSkKZWFzdF9wYWNfc291dGhfbGF0aXR1ZGVzIDwtIHNlcSgwLCB5bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGJ5ID0gLTEpCgojc2V0dXAgZGF0YSB0YWJsZSB0byBwb3B1bGF0ZSBpbiBsb29wLCBzdWJ0cmFjdGluZyBvbmUgdG8gYWxsb3cgZm9yIGJpbnMKZWFzdF9wYWNfc2hlbGZfYXJlYXMgPC0gYXMuZGF0YS50YWJsZShtYXRyaXgobnJvdyA9IChsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xK2xlbmd0aChlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBsYXRpdHVkZV9zdGFydCA6PSBhcy5udW1lcmljKFYxKV1bLCBsYXRpdHVkZV9lbmQgOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yYXN0ZXJhcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfZXF1YWxhcmVhcHJvaiA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX3JnZW9zX2dBcmVhIDo9IGFzLm51bWVyaWMoVjEpXVssIFYxIDo9IE5VTExdCgojbG9vcCBmb3Igbm9ydGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpKSB7CiAgI3NldHRpbmcgdXAgZXh0ZW50IGZvciBzbGljaW5nIGJ5IG1pbiBhbmQgbWF4IGxvbmdpdHVkZXMsIGFuZCBpIHRvIGkrMSBsYXRpdHVkZXMKICBub3J0aF9leHRlbnQgPC0gYyh4bWluKHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHhtYXgod2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2ldLCBlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXNbaSsxXSkKICAKICAjY3JvcCByYXN0ZXIgc2VnZW1lbnQgYmFzZWQgb24gYmluIGV4dGVudAogIHNlZ21lbnRfbm9ydGggPC0gY3JvcCh3ZXN0X2luZF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggbGF0aXR1ZGluYWwgYmluCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X25vcnRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBhbGwgYXJlYSA9IDAKICAgIAogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSAwCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKCiAgCiAgcHJpbnQoaSkKICAgIAogIH0gZWxzZSB7ICNpZiB0aGVyZSBpcyBzaGVsZiBhcmVhIHdpdGhpbiB0aGUgYmluLCBjYWxjdWxhdGUgYXJlYSBvZiBzbGljZQogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X25vcnRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X25vcnRoKV0KICAgIAogICAgI2NvbXB1dGUgYXJlYSBvZiBhbGwgY2VsbHMgaW4gZ2VvX3Jhc3RlcgogICAgI2Z1bGwgYXJlYSAgICAgICAgICA8LSB0b3RhbCAjIGdyaWQgY2VsbHMgICAgICogbWVkaWFuIGNlbGwgYXJlYSAodXNpbmcgbWVkaWFuIGNhcmVzIGxlc3MgYWJvdXQgZXh0cmVtZSB2YWx1ZXMpCiAgICBzZWdtZW50X2FyZWFfcmFzdGVyIDwtIGxlbmd0aChjZWxsX3NpemVfcmFzdGVyKSptZWRpYW4oY2VsbF9zaXplX3Jhc3RlcikgI2luIGttXjIKICAgIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcmFzdGVyIGFyZWEKICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfbm9ydGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X25vcnRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X25vcnRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfbm9ydGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X25vcnRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJhc3RlciBjYWxjdWxhdGlvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfbm9ydGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggcG9seWdvbiBhcmVhIHVzaW5nIHJlZ2VvcyBjYWxjdWxhdGlvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2ksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gICBhcmVhX3JnZW9zX2dBcmVhCiAgCiAgcHJpbnQoaSkKICB9IAp9CgojbG9vcCBmb3Igc291dGgKZm9yIChpIGluIDE6KGxlbmd0aChlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXMpLTEpKSB7CiAgc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIGVhc3RfcGFjX3NvdXRoX2xhdGl0dWRlc1tpKzFdLCBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaV0pICNvcmRlcj0geG1pbiwgeG1heCwgeW1pbiwgeW1heCkKICAKICAjcmFzdGVyIHNlZ21lbnQKICBzZWdtZW50X3NvdXRoIDwtIGNyb3Aod2VzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQoc291dGhfZXh0ZW50KSkKICAKICAjYWRkIGxhdGl0dWRlIGJpbiBpbmZvIHRvIGRhdGEgdGFibGUKICAgIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAibGF0aXR1ZGVfc3RhcnQiXSA8LSBlYXN0X3BhY19zb3V0aF9sYXRpdHVkZXNbaV0KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX2VuZCJdIDwtIGVhc3RfcGFjX3NvdXRoX2xhdGl0dWRlc1tpKzFdCiAgCiAgCiAgaWYoYWxsKGlzLm5hKHZhbHVlcyhzZWdtZW50X3NvdXRoKSkpKSB7ICNpZiB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgd2l0aGluIGEgYmluLCBtZWFuaW5nIHRoZXJlJ3Mgbm8gc2hlbGYgYXJlYSBhdCB0aGF0IGxhdGl0dWRlCgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gMAogICAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3JnZW9zX2dBcmVhIl0gPC0gMAogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgewogIAogICAgI3Jhc3RlciBhcmVhIGNhbGN1bGF0aW9uCiAgICAgICNnZXQgc2l6ZXMgb2YgYWxsIGNlbGxzIGluIHJhc3RlciBba20yXQogICAgY2VsbF9zaXplX3Jhc3RlcjwtYXJlYShzZWdtZW50X3NvdXRoLCBuYS5ybT1UUlVFLCB3ZWlnaHRzPUZBTFNFKQogICAgCiAgICAjZGVsZXRlIE5BcyBmcm9tIHZlY3RvciBvZiBhbGwgcmFzdGVyIGNlbGxzCiAgICBjZWxsX3NpemVfcmFzdGVyPC1jZWxsX3NpemVfcmFzdGVyWyFpcy5uYShzZWdtZW50X3NvdXRoKV0KICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9wYWNfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfcGFjX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSBzZWdtZW50X2FyZWFfcmFzdGVyCiAgICAKICAKICAjY29udmVydCB0byBzcGF0aWFsIHBvbHlnb25zIHRvIGNoZWNrIGFyZWEgY2FsY3VsYXRpb25zCiAgICAKICAjY29udmVydCBzZWdtZW50IGZyb20gcmFzdGVyIHRvIHBvbHlnb24sIGVhY2ggY2VsbCBmcm9tIHRoZSByYXN0ZXIgaXMgYW4gaW5kZXBlbmRlbnQgcG9seWdvbiwgKGRpc3NvbHZlIG1lYW5zIGFsbCBjZWxscyB3aXRoIGEgdmFsdWUgb2YgMSBhcmUgYSBzaW5nbGUgcG9seWdvbiBpZiBjb25uZWN0ZWQpCiAgc2VnbWVudF9zb3V0aC5zcCA8LSByYXN0ZXJUb1BvbHlnb25zKHNlZ21lbnRfc291dGgsIGRpc3NvbHZlID0gVCkKICAKICAjICBJZiB4IGlzIGEgU3BhdGlhbFBvbHlnb25zKiBvYmplY3Q6IGFyZWEgb2YgZWFjaCBzcGF0aWFsIG9iamVjdCBpbiBzcXVhcmVkIG1ldGVycyBpZiB0aGUgQ1JTIGlzIGxvbmdpdHVkZS9sYXRpdHVkZSwgb3IgaW4gc3F1YXJlZCBtYXAgdW5pdHMgKHR5cGljYWxseSBtZXRlcikKICAKICAgICNwcm9qZWN0IHRvIGVxdWFsIGVhcnRoIGFyZWEgcHJvamVjdGlvbgogIHNlZ21lbnRfc291dGguc3AuRUEgPC0gc3BUcmFuc2Zvcm0oc2VnbWVudF9zb3V0aC5zcCwgQ1JTb2JqID0gZXF1YWxhcmVhcHJvamVjdGlvbikKCiAgI2NhbGN1bGF0ZSBhcmVhIG9mIHRoZSBzcGF0aWFsIG9iamVjdCBpbiBtXjIKICAgIHBvbHlnb25fc2l6ZS5zcCA8LSBhcmVhKHNlZ21lbnRfc291dGguc3AuRUEpCgogICAgI2NvbnZlcnQgZnJvbSBtXjIgdG8ga21eMgogICAgc2VnbWVudF9hcmVhX2VxdWFsYXJlYSA8LSBwb2x5Z29uX3NpemUuc3AvMWU2CgogICAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCBhcmVhIG9mIHBvbHlnb24gZnJvbSByYXN0ZXI6OmFyZWEgZnVuY3Rpb24KICBlYXN0X3BhY19zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9wYWNfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEKICAKICAjYW5kIHRoZW4gcGxhaW4gYW5kIHNpbXBsZSBhbHNvIHVzaW5nIHJnZW9zOjpnQXJlYQogIAogIGFyZWFfcmdlb3NfZ0FyZWEgPC0gZ0FyZWEoc2VnbWVudF9zb3V0aC5zcC5FQSkvMWU2CiAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgZnJvbSByZ2VvcyBhcmVhIGNhbGN1bGF0aW9uIGZvciBwcm9qZWN0ZWQgcG9seWdvbgogIGVhc3RfcGFjX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X3BhY19ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2NvbXBhcmUgcmFzdGVyOmFyZWEgY2FsY3VsYXRpb24sIHRvIGVxdWFsIGFyZWEgc3RpbGwgdXNpbmcgcmFzdGVyOjphcmVhIGZ1bmN0aW9uLCB0byByZ2Vvczo6Z0FyZWEgZnVuY3Rpb24gZm9yIHBvbHlnb25zCgpnZ3Bsb3QoZGF0YSA9IGVhc3RfcGFjX3NoZWxmX2FyZWFzKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yZ2Vvc19nQXJlYSksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAwLjUpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIHkgPSBhcmVhX3Jhc3RlcmFyZWEpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9lcXVhbGFyZWFwcm9qKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuNSkgKwogIGxhYnMoeCA9ICJMYXRpdHVkZSIsIHkgPSAiQXJlYSBrbV4yIikgKwogIHRoZW1lX2NsYXNzaWMoKQoKY29yKGVhc3RfcGFjX3NoZWxmX2FyZWFzWywzOjVdLCB1c2UgPSAiY29tcGxldGUub2JzIikKCnNhdmUoZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGZpbGUgPSAiZWFzdF9wYWNfc2hlbGZfYXJlYXMuUkRhdGEiKQoKYGBgCgpgYGB7ciBwZXJjZW50IHNoaWZ0IGVhc3Rlcm4gcGFjaWZpY30KZWFzdF9wYWNfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCmVhc3RfcGFjX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgplYXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gZWFzdF9wYWNfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKZWFzdF9wYWNfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUoZWFzdF9wYWNfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKV2VzdGVybiBBdGxhbnRpYwoKd2VzdF9hdGxfc3BkZl9tYXNrCgpgYGB7ciBzcGxpdCByYXN0ZXIgZm9yIHdlc3Rlcm4gYXRsYW50aWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCAwLCB5bWF4KHdlc3RfYXRsX3NwZGZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB5bWluKHdlc3RfYXRsX3NwZGZfbWFza18xcyksIDApCgojY3JvcCB3ZXN0X2F0bCByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKd2VzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKd2VzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciB3ZXN0IGF0bGFudGljCndlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCndlc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfYXRsX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfYXRsX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfYXRsX3NwZGZfbWFza18xcyksIHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9hdGxfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9hdGxfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2F0bF9zcGRmX21hc2tfMXMpLCB3ZXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfYXRsX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcih3ZXN0X2F0bF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgd2VzdGVybiBhdGxhbnRpY30Kd2VzdF9hdGxfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfYXRsX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9hdGxfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9hdGxfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKRWFzdGVybiBBdGxhbnRpYwoKZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrCgpgYGB7ciBzcGxpdCByYXN0ZXIgZm9yIGVhc3Rlcm4gYXRsYW50aWN9Cm5vcnRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCAwLCB5bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcykpCnNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB5bWluKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIDApCgojY3JvcCBlYXN0X2F0bCByYXN0ZXIgYWJvdmUgYW5kIGJlbG93IDAKZWFzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfbm9ydGggPC0gY3JvcChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMsIGV4dGVudChub3J0aF9leHRlbnQpKQoKZWFzdF9hdGxfc3BkZl9zaGlmdF9hZ2dfc291dGggPC0gY3JvcChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMsIGV4dGVudChzb3V0aF9leHRlbnQpKQoKI3VuZm9ydHVuYXRlbHksIEkgdGhpbmsgSSBtYXkgaGF2ZSB0byBqdXN0IGRvIHRoaXMgbWFudWFsbHkgKHVnbHksIEkga25vdykKCiNhbGwgY2h1bmtzIGZvciBlYXN0IGF0bGFudGljCmVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBieSA9IDEpCmVhc3RfYXRsX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCmVhc3RfYXRsX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgoZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCB4bWF4KGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcyksIGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXSwgZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3AoZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlc1tpXQogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9hdGxfc3BkZl9ub2J1Zl9tYXNrXzFzKSwgeG1heChlYXN0X2F0bF9zcGRmX25vYnVmX21hc2tfMXMpLCBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKGVhc3RfYXRsX3NwZGZfbm9idWZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9hdGxfc291dGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2F0bF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIGVhc3RfYXRsX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2F0bF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgZWFzdF9hdGxfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfYXRsX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICBlYXN0X2F0bF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9hdGxfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSBlYXN0X2F0bF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcihlYXN0X2F0bF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgZWFzdGVybiBhdGxhbnRpY30KZWFzdF9hdGxfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCmVhc3RfYXRsX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgplYXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gZWFzdF9hdGxfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKZWFzdF9hdGxfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUoZWFzdF9hdGxfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKV2VzdGVybiBJbmRpYW4KCndlc3RfaW5kX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciB3ZXN0ZXJuIGluZGlhbn0Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIDAsIHltYXgod2VzdF9pbmRfc3BkZl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHltaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCkKCiNjcm9wIHdlc3RfaW5kIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgp3ZXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIHdlc3QgaW5kaWFuCndlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCndlc3RfaW5kX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCndlc3RfaW5kX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCndlc3RfaW5kX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbih3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KHdlc3RfaW5kX3NwZGZfbWFza18xcyksIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXSwgd2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3Aod2VzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgod2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4od2VzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heCh3ZXN0X2luZF9zcGRmX21hc2tfMXMpLCB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKHdlc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gd2VzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSB3ZXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIHdlc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aCh3ZXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgd2VzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKHdlc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICB3ZXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgod2VzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcih3ZXN0X2luZF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCmBgYAoKYGBge3IgcGVyY2VudCBzaGlmdCB3ZXN0ZXJuIGluZGlhbn0Kd2VzdF9pbmRfc2hlbGZfYXJlYXNbLCBwZXJjZW50X2NoYW5nZSA6PSAoYXJlYV9lcXVhbGFyZWFwcm9qLXNoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKSkvc2hpZnQoYXJlYV9lcXVhbGFyZWFwcm9qLCB0eXBlID0gImxhZyIpXVssYXJlYV8xMDAwcyA6PSBhcmVhX2VxdWFsYXJlYXByb2ovMTAwMF0KCndlc3RfaW5kX3NoZWxmX2FyZWFzWywgY2hhbmdlX2Fib3ZlXzJmb2xkIDo9IGlmZWxzZSgocGVyY2VudF9jaGFuZ2U+PTEgJiBwZXJjZW50X2NoYW5nZTxJbmYpLCAxLCBpZmVsc2UocGVyY2VudF9jaGFuZ2U8PS0wLjUsIC0xLCAwKSldCgp3ZXN0X2luZF9zaGVsZl9hcmVhc19oaWdobGlnaHQgPC0gd2VzdF9pbmRfc2hlbGZfYXJlYXNbY2hhbmdlX2Fib3ZlXzJmb2xkICE9IDAsXQoKd2VzdF9pbmRfc2hlbGZfYXJlYXNfc3RhdHMgPC0gdGFibGUod2VzdF9pbmRfc2hlbGZfYXJlYXNbLC4oY2hhbmdlX2Fib3ZlXzJmb2xkKV0pCmBgYAoKRWFzdGVybiBJbmRpYW4KCmVhc3RfaW5kX3NwZGZfbWFzawoKYGBge3Igc3BsaXQgcmFzdGVyIGZvciBlYXN0ZXJuIGluZGlhbn0Kbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIDAsIHltYXgoZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSkKc291dGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIHltaW4oZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgMCkKCiNjcm9wIGVhc3RfaW5kIHJhc3RlciBhYm92ZSBhbmQgYmVsb3cgMAplYXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19ub3J0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KG5vcnRoX2V4dGVudCkpCgplYXN0X2luZF9zcGRmX3NoaWZ0X2FnZ19zb3V0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCgojdW5mb3J0dW5hdGVseSwgSSB0aGluayBJIG1heSBoYXZlIHRvIGp1c3QgZG8gdGhpcyBtYW51YWxseSAodWdseSwgSSBrbm93KQoKI2FsbCBjaHVua3MgZm9yIGVhc3QgaW5kaWFuCmVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1heChlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IDEpCmVhc3RfaW5kX3NvdXRoX2xhdGl0dWRlcyA8LSBzZXEoMCwgeW1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBieSA9IC0xKQoKI3NldHVwIGRhdGEgdGFibGUgdG8gcG9wdWxhdGUgaW4gbG9vcCwgc3VidHJhY3Rpbmcgb25lIHRvIGFsbG93IGZvciBiaW5zCmVhc3RfaW5kX3NoZWxmX2FyZWFzIDwtIGFzLmRhdGEudGFibGUobWF0cml4KG5yb3cgPSAobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMStsZW5ndGgoZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmVhc3RfaW5kX3NoZWxmX2FyZWFzWywgbGF0aXR1ZGVfc3RhcnQgOj0gYXMubnVtZXJpYyhWMSldWywgbGF0aXR1ZGVfZW5kIDo9IGFzLm51bWVyaWMoVjEpXVssIGFyZWFfcmFzdGVyYXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBhcmVhX2VxdWFsYXJlYXByb2ogOj0gYXMubnVtZXJpYyhWMSldWywgYXJlYV9yZ2Vvc19nQXJlYSA6PSBhcy5udW1lcmljKFYxKV1bLCBWMSA6PSBOVUxMXQoKI2xvb3AgZm9yIG5vcnRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSkgewogICNzZXR0aW5nIHVwIGV4dGVudCBmb3Igc2xpY2luZyBieSBtaW4gYW5kIG1heCBsb25naXR1ZGVzLCBhbmQgaSB0byBpKzEgbGF0aXR1ZGVzCiAgbm9ydGhfZXh0ZW50IDwtIGMoeG1pbihlYXN0X2luZF9zcGRmX21hc2tfMXMpLCB4bWF4KGVhc3RfaW5kX3NwZGZfbWFza18xcyksIGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXSwgZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzW2krMV0pCiAgCiAgI2Nyb3AgcmFzdGVyIHNlZ2VtZW50IGJhc2VkIG9uIGJpbiBleHRlbnQKICBzZWdtZW50X25vcnRoIDwtIGNyb3AoZWFzdF9pbmRfc3BkZl9tYXNrXzFzLCBleHRlbnQobm9ydGhfZXh0ZW50KSkKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIGxhdGl0dWRpbmFsIGJpbgogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9zdGFydCJdIDwtIGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlc1tpXQogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXNbaSsxXQogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9ub3J0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgYWxsIGFyZWEgPSAwCiAgICAKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gMAogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2ksICJhcmVhX3Jhc3RlcmFyZWEiXSA8LSAwCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAwCgogIAogIHByaW50KGkpCiAgICAKICB9IGVsc2UgeyAjaWYgdGhlcmUgaXMgc2hlbGYgYXJlYSB3aXRoaW4gdGhlIGJpbiwgY2FsY3VsYXRlIGFyZWEgb2Ygc2xpY2UKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9ub3J0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9ub3J0aCldCiAgICAKICAgICNjb21wdXRlIGFyZWEgb2YgYWxsIGNlbGxzIGluIGdlb19yYXN0ZXIKICAgICNmdWxsIGFyZWEgICAgICAgICAgPC0gdG90YWwgIyBncmlkIGNlbGxzICAgICAqIG1lZGlhbiBjZWxsIGFyZWEgKHVzaW5nIG1lZGlhbiBjYXJlcyBsZXNzIGFib3V0IGV4dHJlbWUgdmFsdWVzKQogICAgc2VnbWVudF9hcmVhX3Jhc3RlciA8LSBsZW5ndGgoY2VsbF9zaXplX3Jhc3RlcikqbWVkaWFuKGNlbGxfc2l6ZV9yYXN0ZXIpICNpbiBrbV4yCiAgICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHJhc3RlciBhcmVhCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIHNlZ21lbnRfYXJlYV9yYXN0ZXIKICAgIAogICNjb252ZXJ0IHRvIHNwYXRpYWwgcG9seWdvbnMgdG8gY2hlY2sgYXJlYSBjYWxjdWxhdGlvbnMKICAgIAogICNjb252ZXJ0IHNlZ21lbnQgZnJvbSByYXN0ZXIgdG8gcG9seWdvbiwgZWFjaCBjZWxsIGZyb20gdGhlIHJhc3RlciBpcyBhbiBpbmRlcGVuZGVudCBwb2x5Z29uLCAoZGlzc29sdmUgbWVhbnMgYWxsIGNlbGxzIHdpdGggYSB2YWx1ZSBvZiAxIGFyZSBhIHNpbmdsZSBwb2x5Z29uIGlmIGNvbm5lY3RlZCkKICBzZWdtZW50X25vcnRoLnNwIDwtIHJhc3RlclRvUG9seWdvbnMoc2VnbWVudF9ub3J0aCwgZGlzc29sdmUgPSBUKQogIAogICMgIElmIHggaXMgYSBTcGF0aWFsUG9seWdvbnMqIG9iamVjdDogYXJlYSBvZiBlYWNoIHNwYXRpYWwgb2JqZWN0IGluIHNxdWFyZWQgbWV0ZXJzIGlmIHRoZSBDUlMgaXMgbG9uZ2l0dWRlL2xhdGl0dWRlLCBvciBpbiBzcXVhcmVkIG1hcCB1bml0cyAodHlwaWNhbGx5IG1ldGVyKQogIAogICAgI3Byb2plY3QgdG8gZXF1YWwgZWFydGggYXJlYSBwcm9qZWN0aW9uCiAgc2VnbWVudF9ub3J0aC5zcC5FQSA8LSBzcFRyYW5zZm9ybShzZWdtZW50X25vcnRoLnNwLCBDUlNvYmogPSBlcXVhbGFyZWFwcm9qZWN0aW9uKQoKICAjY2FsY3VsYXRlIGFyZWEgb2YgdGhlIHNwYXRpYWwgb2JqZWN0IGluIG1eMgogICAgcG9seWdvbl9zaXplLnNwIDwtIGFyZWEoc2VnbWVudF9ub3J0aC5zcC5FQSkKCiAgICAjY29udmVydCBmcm9tIG1eMiB0byBrbV4yCiAgICBzZWdtZW50X2FyZWFfZXF1YWxhcmVhIDwtIHBvbHlnb25fc2l6ZS5zcC8xZTYKCiAgICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByYXN0ZXIgY2FsY3VsYXRpb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9lcXVhbGFyZWFwcm9qIl0gPC0gc2VnbWVudF9hcmVhX2VxdWFsYXJlYQogIAogICNhbmQgdGhlbiBwbGFpbiBhbmQgc2ltcGxlIGFsc28gdXNpbmcgcmdlb3M6OmdBcmVhCiAgCiAgYXJlYV9yZ2Vvc19nQXJlYSA8LSBnQXJlYShzZWdtZW50X25vcnRoLnNwLkVBKS8xZTYKICAKICAjcG9wdWxhdGUgZGF0YSB0YWJsZSB3aXRoIHBvbHlnb24gYXJlYSB1c2luZyByZWdlb3MgY2FsY3VsYXRpb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtICAgYXJlYV9yZ2Vvc19nQXJlYQogIAogIHByaW50KGkpCiAgfSAKfQoKI2xvb3AgZm9yIHNvdXRoCmZvciAoaSBpbiAxOihsZW5ndGgoZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzKS0xKSkgewogIHNvdXRoX2V4dGVudCA8LSBjKHhtaW4oZWFzdF9pbmRfc3BkZl9tYXNrXzFzKSwgeG1heChlYXN0X2luZF9zcGRmX21hc2tfMXMpLCBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXSwgZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldKSAjb3JkZXI9IHhtaW4sIHhtYXgsIHltaW4sIHltYXgpCiAgCiAgI3Jhc3RlciBzZWdtZW50CiAgc2VnbWVudF9zb3V0aCA8LSBjcm9wKGVhc3RfaW5kX3NwZGZfbWFza18xcywgZXh0ZW50KHNvdXRoX2V4dGVudCkpCiAgCiAgI2FkZCBsYXRpdHVkZSBiaW4gaW5mbyB0byBkYXRhIHRhYmxlCiAgICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImxhdGl0dWRlX3N0YXJ0Il0gPC0gZWFzdF9pbmRfc291dGhfbGF0aXR1ZGVzW2ldCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJsYXRpdHVkZV9lbmQiXSA8LSBlYXN0X2luZF9zb3V0aF9sYXRpdHVkZXNbaSsxXQogIAogIAogIGlmKGFsbChpcy5uYSh2YWx1ZXMoc2VnbWVudF9zb3V0aCkpKSkgeyAjaWYgdGhlcmUncyBubyBzaGVsZiBhcmVhIHdpdGhpbiBhIGJpbiwgbWVhbmluZyB0aGVyZSdzIG5vIHNoZWxmIGFyZWEgYXQgdGhhdCBsYXRpdHVkZQoKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfZXF1YWxhcmVhcHJvaiJdIDwtIDAKICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmFzdGVyYXJlYSJdIDwtIDAKICAgIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yZ2Vvc19nQXJlYSJdIDwtIDAKICAKICBwcmludChpKQogICAgCiAgfSBlbHNlIHsKICAKICAgICNyYXN0ZXIgYXJlYSBjYWxjdWxhdGlvbgogICAgICAjZ2V0IHNpemVzIG9mIGFsbCBjZWxscyBpbiByYXN0ZXIgW2ttMl0KICAgIGNlbGxfc2l6ZV9yYXN0ZXI8LWFyZWEoc2VnbWVudF9zb3V0aCwgbmEucm09VFJVRSwgd2VpZ2h0cz1GQUxTRSkKICAgIAogICAgI2RlbGV0ZSBOQXMgZnJvbSB2ZWN0b3Igb2YgYWxsIHJhc3RlciBjZWxscwogICAgY2VsbF9zaXplX3Jhc3RlcjwtY2VsbF9zaXplX3Jhc3RlclshaXMubmEoc2VnbWVudF9zb3V0aCldCiAgICAjY29tcHV0ZSBhcmVhIG9mIGFsbCBjZWxscyBpbiBnZW9fcmFzdGVyCiAgICAjZnVsbCBhcmVhICAgICAgICAgIDwtIHRvdGFsICMgZ3JpZCBjZWxscyAgICAgKiBtZWRpYW4gY2VsbCBhcmVhICh1c2luZyBtZWRpYW4gY2FyZXMgbGVzcyBhYm91dCBleHRyZW1lIHZhbHVlcykKICAgIHNlZ21lbnRfYXJlYV9yYXN0ZXIgPC0gbGVuZ3RoKGNlbGxfc2l6ZV9yYXN0ZXIpKm1lZGlhbihjZWxsX3NpemVfcmFzdGVyKQogICAgCiAgI3BvcHVsYXRlIGRhdGEgdGFibGUgd2l0aCByYXN0ZXIgYXJlYQogIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2krKGxlbmd0aChlYXN0X2luZF9ub3J0aF9sYXRpdHVkZXMpLTEpLCAiYXJlYV9yYXN0ZXJhcmVhIl0gPC0gc2VnbWVudF9hcmVhX3Jhc3RlcgogICAgCiAgCiAgI2NvbnZlcnQgdG8gc3BhdGlhbCBwb2x5Z29ucyB0byBjaGVjayBhcmVhIGNhbGN1bGF0aW9ucwogICAgCiAgI2NvbnZlcnQgc2VnbWVudCBmcm9tIHJhc3RlciB0byBwb2x5Z29uLCBlYWNoIGNlbGwgZnJvbSB0aGUgcmFzdGVyIGlzIGFuIGluZGVwZW5kZW50IHBvbHlnb24sIChkaXNzb2x2ZSBtZWFucyBhbGwgY2VsbHMgd2l0aCBhIHZhbHVlIG9mIDEgYXJlIGEgc2luZ2xlIHBvbHlnb24gaWYgY29ubmVjdGVkKQogIHNlZ21lbnRfc291dGguc3AgPC0gcmFzdGVyVG9Qb2x5Z29ucyhzZWdtZW50X3NvdXRoLCBkaXNzb2x2ZSA9IFQpCiAgCiAgIyAgSWYgeCBpcyBhIFNwYXRpYWxQb2x5Z29ucyogb2JqZWN0OiBhcmVhIG9mIGVhY2ggc3BhdGlhbCBvYmplY3QgaW4gc3F1YXJlZCBtZXRlcnMgaWYgdGhlIENSUyBpcyBsb25naXR1ZGUvbGF0aXR1ZGUsIG9yIGluIHNxdWFyZWQgbWFwIHVuaXRzICh0eXBpY2FsbHkgbWV0ZXIpCiAgCiAgICAjcHJvamVjdCB0byBlcXVhbCBlYXJ0aCBhcmVhIHByb2plY3Rpb24KICBzZWdtZW50X3NvdXRoLnNwLkVBIDwtIHNwVHJhbnNmb3JtKHNlZ21lbnRfc291dGguc3AsIENSU29iaiA9IGVxdWFsYXJlYXByb2plY3Rpb24pCgogICNjYWxjdWxhdGUgYXJlYSBvZiB0aGUgc3BhdGlhbCBvYmplY3QgaW4gbV4yCiAgICBwb2x5Z29uX3NpemUuc3AgPC0gYXJlYShzZWdtZW50X3NvdXRoLnNwLkVBKQoKICAgICNjb252ZXJ0IGZyb20gbV4yIHRvIGttXjIKICAgIHNlZ21lbnRfYXJlYV9lcXVhbGFyZWEgPC0gcG9seWdvbl9zaXplLnNwLzFlNgoKICAgICNwb3B1bGF0ZSBkYXRhIHRhYmxlIHdpdGggYXJlYSBvZiBwb2x5Z29uIGZyb20gcmFzdGVyOjphcmVhIGZ1bmN0aW9uCiAgZWFzdF9pbmRfc2hlbGZfYXJlYXNbaSsobGVuZ3RoKGVhc3RfaW5kX25vcnRoX2xhdGl0dWRlcyktMSksICJhcmVhX2VxdWFsYXJlYXByb2oiXSA8LSBzZWdtZW50X2FyZWFfZXF1YWxhcmVhCiAgCiAgI2FuZCB0aGVuIHBsYWluIGFuZCBzaW1wbGUgYWxzbyB1c2luZyByZ2Vvczo6Z0FyZWEKICAKICBhcmVhX3JnZW9zX2dBcmVhIDwtIGdBcmVhKHNlZ21lbnRfc291dGguc3AuRUEpLzFlNgogIAogICNwb3B1bGF0ZSBkYXRhIHRhYmxlIGZyb20gcmdlb3MgYXJlYSBjYWxjdWxhdGlvbiBmb3IgcHJvamVjdGVkIHBvbHlnb24KICBlYXN0X2luZF9zaGVsZl9hcmVhc1tpKyhsZW5ndGgoZWFzdF9pbmRfbm9ydGhfbGF0aXR1ZGVzKS0xKSwgImFyZWFfcmdlb3NfZ0FyZWEiXSA8LSAgIGFyZWFfcmdlb3NfZ0FyZWEKICAKICBwcmludChpKQogIH0gCn0KCiNjb21wYXJlIHJhc3RlcjphcmVhIGNhbGN1bGF0aW9uLCB0byBlcXVhbCBhcmVhIHN0aWxsIHVzaW5nIHJhc3Rlcjo6YXJlYSBmdW5jdGlvbiwgdG8gcmdlb3M6OmdBcmVhIGZ1bmN0aW9uIGZvciBwb2x5Z29ucwoKZ2dwbG90KGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhcykgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfcmdlb3NfZ0FyZWEpLCBjb2xvciA9ICJwdXJwbGUiLCBzaXplID0gMC41KSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCB5ID0gYXJlYV9yYXN0ZXJhcmVhKSwgY29sb3IgPSAiZGFya2dyZWVuIiwgc2l6ZSA9IDAuNSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWFfZXF1YWxhcmVhcHJvaiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjUpICsKICBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gIkFyZWEga21eMiIpICsKICB0aGVtZV9jbGFzc2ljKCkKCmNvcihlYXN0X2luZF9zaGVsZl9hcmVhc1ssMzo1XSwgdXNlID0gImNvbXBsZXRlLm9icyIpCgpgYGAKCmBgYHtyIHBlcmNlbnQgc2hpZnQgZWFzdGVybiBpbmRpYW59CmVhc3RfaW5kX3NoZWxmX2FyZWFzWywgcGVyY2VudF9jaGFuZ2UgOj0gKGFyZWFfZXF1YWxhcmVhcHJvai1zaGlmdChhcmVhX2VxdWFsYXJlYXByb2osIHR5cGUgPSAibGFnIikpL3NoaWZ0KGFyZWFfZXF1YWxhcmVhcHJvaiwgdHlwZSA9ICJsYWciKV1bLGFyZWFfMTAwMHMgOj0gYXJlYV9lcXVhbGFyZWFwcm9qLzEwMDBdCgplYXN0X2luZF9zaGVsZl9hcmVhc1ssIGNoYW5nZV9hYm92ZV8yZm9sZCA6PSBpZmVsc2UoKHBlcmNlbnRfY2hhbmdlPj0xICYgcGVyY2VudF9jaGFuZ2U8SW5mKSwgMSwgaWZlbHNlKHBlcmNlbnRfY2hhbmdlPD0tMC41LCAtMSwgMCkpXQoKZWFzdF9pbmRfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0IDwtIGVhc3RfaW5kX3NoZWxmX2FyZWFzW2NoYW5nZV9hYm92ZV8yZm9sZCAhPSAwLF0KCmVhc3RfaW5kX3NoZWxmX2FyZWFzX3N0YXRzIDwtIHRhYmxlKGVhc3RfaW5kX3NoZWxmX2FyZWFzWywuKGNoYW5nZV9hYm92ZV8yZm9sZCldKQpgYGAKClBsb3RzIG9mIGxhdGl0dWRlIHZlcnN1cyBoYWJpdGF0IGF2YWlsYWJpbGl0eQoKYGBge3IgcGxvdHMgbGF0aXR1ZGUgaGFiaXRhdCBhdmFpbGFiaWxpdHl9CihhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9pbmRfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsKICBnZW9tX2xpbmUoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogIGdlb21fcnVnKGRhdGEgPSBlYXN0X2luZF9zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICMjYW5ub3RhdGUoInRleHQiLCB4ID0yMiwgeSA9IDcwMDAwLCBsYWJlbCA9ICJFYXN0ZXJuIEluZGlhbiBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfaW5kX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKSkKCgogIGdnc2F2ZShhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kLCBmaWxlbmFtZSA9ICJhcmVhX2xhdGl0dWRlX2Vhc3RfaW5kLmpwZyIsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKCmFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQgIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2luZF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfaW5kX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogICAgZ2VvbV9ydWcoZGF0YSA9IGVhc3RfaW5kX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgY29sb3IgPSBhcy5mYWN0b3IoY2hhbmdlX2Fib3ZlXzJmb2xkKSkpICsKIGxhYnMoeCA9ICJMYXRpdHVkZSIsIHkgPSBleHByZXNzaW9uKHBhc3RlKCJBcmVhICgxMDAwcyBvZiAiLCBrbV57Mn0sIikiKSkpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIkluc3RhbmNlcyBvZiAyIEZvbGRcbiBIYWJpdGF0IENoYW5nZSIsIGxhYmVscyA9IGMoIkNvbnRyYWN0aW9uIiwgIkV4cGFuc2lvbiIpKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeCA9IDMwLCB5ID0gMzMwMDAsIGxhYmVsID0gIldlc3Rlcm4gSW5kaWFuIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbih3ZXN0X2luZF9zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgod2VzdF9pbmRfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpCgogIGdnc2F2ZShhcmVhX2xhdGl0dWRlX3dlc3RfaW5kLCBmaWxlbmFtZSA9ICJhcmVhX2xhdGl0dWRlX3dlc3RfaW5kLmpwZyIsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKCmFyZWFfbGF0aXR1ZGVfd2VzdF9hdGwgIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcyksIHNoYXBlID0xOCkgKyAKICBnZW9tX2xpbmUoZGF0YSA9IHdlc3RfYXRsX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSkgKwogIGdlb21fcnVnKGRhdGEgPSB3ZXN0X2F0bF9zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSA4MCwgeSA9IDEyMDAwMCwgbGFiZWwgPSAiV2VzdGVybiBBdGxhbnRpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4od2VzdF9hdGxfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KHdlc3RfYXRsX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV93ZXN0X2F0bCwgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV93ZXN0X2F0bC5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgphcmVhX2xhdGl0dWRlX2Vhc3RfYXRsICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9hdGxfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X2F0bF9zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcykpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9hdGxfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiSW5zdGFuY2VzIG9mIDIgRm9sZFxuIEhhYml0YXQgQ2hhbmdlIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiRXhwYW5zaW9uIikpICsKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gODIuNSwgeSA9IDExMDAwMCwgbGFiZWwgPSAiRWFzdGVybiBBdGxhbnRpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9hdGxfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfYXRsX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV9lYXN0X2F0bCwgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV9lYXN0X2F0bC5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgphcmVhX2xhdGl0dWRlX2Vhc3RfcGFjICA8LSBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpLCBzaGFwZSA9MTgpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBlYXN0X3BhY19zaGVsZl9hcmVhcywgYWVzKHg9bGF0aXR1ZGVfc3RhcnQsIHk9YXJlYV8xMDAwcykpICsKICBnZW9tX3J1ZyhkYXRhID0gZWFzdF9wYWNfc2hlbGZfYXJlYXNfaGlnaGxpZ2h0LCBhZXMoeCA9IGxhdGl0dWRlX3N0YXJ0LCBjb2xvciA9IGFzLmZhY3RvcihjaGFuZ2VfYWJvdmVfMmZvbGQpKSkgKwogbGFicyh4ID0gIkxhdGl0dWRlIiwgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkFyZWEgKDEwMDBzIG9mICIsIGttXnsyfSwiKSIpKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiSW5zdGFuY2VzIG9mIDIgRm9sZFxuIEhhYml0YXQgQ2hhbmdlIiwgbGFiZWxzID0gYygiQ29udHJhY3Rpb24iLCAiRXhwYW5zaW9uIikpICsKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gODAsIHkgPSAxMzAwMDAsIGxhYmVsID0gIkVhc3Rlcm4gUGFjaWZpYyBPY2VhbiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgeGxpbShtaW4oZWFzdF9wYWNfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSwgbWF4KGVhc3RfcGFjX3NoZWxmX2FyZWFzJGxhdGl0dWRlX2VuZCkpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDQwLCAxMCwgMTApKQoKICBnZ3NhdmUoYXJlYV9sYXRpdHVkZV9lYXN0X3BhYywgZmlsZW5hbWUgPSAiYXJlYV9sYXRpdHVkZV9lYXN0X3BhYy5qcGciLCBoZWlnaHQgPSA0LCB1bml0cyA9IGMoImluIikpCgoKKGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzLCBhZXMoeD1sYXRpdHVkZV9zdGFydCwgeT1hcmVhXzEwMDBzKSwgc2hhcGUgPTE4KSArIAogIGdlb21fbGluZShkYXRhID0gd2VzdF9wYWNfc2hlbGZfYXJlYXMsIGFlcyh4PWxhdGl0dWRlX3N0YXJ0LCB5PWFyZWFfMTAwMHMpKSArCiAgI2dlb21fcG9pbnQoZGF0YSA9IHdlc3RfcGFjX3NoZWxmX2FyZWFzX2hpZ2hsaWdodCwgYWVzKHggPSBsYXRpdHVkZV9zdGFydCwgeSA9IGFyZWEpLCBzaGFwZSA9MTksIGNvbG9yID0gInNlYWdyZWVuNCIsIHNpemUgPSAyKSArIAogIGdlb21fcnVnKGRhdGEgPSB3ZXN0X3BhY19zaGVsZl9hcmVhc19oaWdobGlnaHQsIGFlcyh4ID0gbGF0aXR1ZGVfc3RhcnQsIGNvbG9yID0gYXMuZmFjdG9yKGNoYW5nZV9hYm92ZV8yZm9sZCkpKSArCiBsYWJzKHggPSAiTGF0aXR1ZGUiLCB5ID0gZXhwcmVzc2lvbihwYXN0ZSgiQXJlYSAoMTAwMHMgb2YgIiwga21eezJ9LCIpIikpKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJJbnN0YW5jZXMgb2YgMiBGb2xkXG4gSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCJDb250cmFjdGlvbiIsICJFeHBhbnNpb24iKSkgKwogICNhbm5vdGF0ZSgidGV4dCIsIHggPSA5MCwgeSA9IDEzMDAwMCwgbGFiZWwgPSAiV2VzdGVybiBQYWNpZmljIE9jZWFuIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICB4bGltKG1pbih3ZXN0X3BhY19zaGVsZl9hcmVhcyRsYXRpdHVkZV9lbmQpLCBtYXgod2VzdF9wYWNfc2hlbGZfYXJlYXMkbGF0aXR1ZGVfZW5kKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgNDAsIDEwLCAxMCkpKQoKICAKCiAgZ2dzYXZlKGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMsIGZpbGVuYW1lID0gImFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMuanBnIiwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQoKYGBgCgpIb3cgbWFueSBleHBlcmllbmNlICdzaWduaWZpY2FudCcgY2hhbmdlcyBpbiBoYWJpdGF0IChhdCBsZWFzdCAtNTAlIG9yICsyMDAlIGNoYW5nZSBmcm9tIG9uZSBiaW4gdG8gYW5vdGhlcikgSSB3aWxsIGdvIHdpdGggSVVDTiA1MCUgbG9zcyAtPiB2dWxuZXJhYmxlIHNwZWNpZXMgZGVzaWduYXRpb24uCgpCaW4gc2hpZnRzIC0tPiBjb250cmFjdGlvbnMgKGxvc3Mgb2YgNTAlKSB2ZXJzdXMgZXhwYW5zaW9ucyAoZ2FpbiBvZiAyMDAlKSB2ZXJzdXMgbmV1dHJhbApgYGB7ciBiaW4gc2hpZnQgY2F0ZWdvcml6YXRpb259CiNjYWxsIGFsbCBvYmplY3RzIGluIGVudmlyb25tZW50IHdpdGggInN0YXRzIiBzdHJpbmcKc3RhdHNfc3RyaW5nPC1ncmVwKCJfc3RhdHMiLG5hbWVzKC5HbG9iYWxFbnYpLHZhbHVlPVRSVUUpCnN0YXRzX3N0cmluZ19saXN0PC1kby5jYWxsKCJsaXN0IixtZ2V0KHN0YXRzX3N0cmluZykpCm5hbWVzKHN0YXRzX3N0cmluZ19saXN0KSA8LSBjKCJFYXN0ZXJuIEluZGlhbiBPY2VhbiIgLCJXZXN0ZXJuIFBhY2lmaWMgT2NlYW4iICwiRWFzdGVybiBQYWNpZmljIE9jZWFuIiAsIldlc3Rlcm4gQXRsYW50aWMgT2NlYW4iICwiV2VzdGVybiBJbmRpYW4gT2NlYW4iICwiRWFzdGVybiBBdGxhbnRpYyBPY2VhbiIpCgpzaWduaWZpY2FudF9jaGFuZ2VzIDwtIGFzLmRhdGEudGFibGUocmJpbmQoc3RhdHNfc3RyaW5nX2xpc3RbWzFdXSxzdGF0c19zdHJpbmdfbGlzdFtbMl1dLHN0YXRzX3N0cmluZ19saXN0W1szXV0sc3RhdHNfc3RyaW5nX2xpc3RbWzRdXSxzdGF0c19zdHJpbmdfbGlzdFtbNV1dLHN0YXRzX3N0cmluZ19saXN0W1s2XV0pKQoKY29sbmFtZXMoc2lnbmlmaWNhbnRfY2hhbmdlcykgPC0gYygiY29udHJhY3Rpb24iLCAibmV1dHJhbCIsICJleHBhbnNpb24iKQoKc2lnbmlmaWNhbnRfY2hhbmdlc1ssIHJlZ2lvbiA6PSBuYW1lcyhzdGF0c19zdHJpbmdfbGlzdCldWyx0b3RhbF9iaW5zIDo9IGNvbnRyYWN0aW9uICsgbmV1dHJhbCArIGV4cGFuc2lvbl1bLGNvbnRyYWN0aW9uX3BlcmNlbnQgOj0gY29udHJhY3Rpb24vdG90YWxfYmluc11bLG5ldXRyYWxfcGVyY2VudCA6PSBuZXV0cmFsL3RvdGFsX2JpbnNdWyxleHBhbnNpb25fcGVyY2VudCA6PSBleHBhbnNpb24vdG90YWxfYmluc10KCiNtZWx0IHRvIHBsb3QKc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nIDwtIG1lbHQoc2lnbmlmaWNhbnRfY2hhbmdlcywgaWQudmFycyA9IGMoInJlZ2lvbiIpLCB2YXJpYWJsZS5uYW1lID0gImNoYW5nZV90eXBlIiwgbWVhc3VyZS52YXJzID0gYygiY29udHJhY3Rpb25fcGVyY2VudCIsICJuZXV0cmFsX3BlcmNlbnQiLCAiZXhwYW5zaW9uX3BlcmNlbnQiKSkKCmJsYW5rX3RoZW1lIDwtIHRoZW1lX21pbmltYWwoKSsKICB0aGVtZSgKICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwKICBwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwKICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTQsIGZhY2U9ImJvbGQiKQogICkKCmdncGxvdChkYXRhID0gc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nLCBhZXMoeD0iIiwgeSA9IHZhbHVlLCBmaWxsID0gY2hhbmdlX3R5cGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSkgKwogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtzYWxtb24iLCAiYXp1cmUyIiwgImN5YW4zIiksIG5hbWUgPSAiSGFiaXRhdCBDaGFuZ2UiLCBsYWJlbHMgPSBjKCI+PSAyIEZvbGQgQ29udHJhY3Rpb24iLCAiPCAyIEZvbGQgQ2hhbmdlIiwgIj49IDIgRm9sZCBFeHBhbnNpb24iKSkgKwogIGZhY2V0X3dyYXAofnJlZ2lvbikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQodmFsdWUqMTAwLDEpLCIlIikpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC4xKSwgc2l6ZSA9IDIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZCA9IGMoMCwwKSkgKwogIGJsYW5rX3RoZW1lICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpCgpnZ3NhdmUoZmlsZW5hbWUgPSAiaGFiaXRhdGxvc3NfZ2Fpbl8yZm9sZC5wZGYiKQpgYGAKCk5vdywgSSBzaG91bGQgbWFrZSBtYXBzIGZvciBlYWNoIG9mIHRoZXNlIHJlZ2lvbnMKClVzZWQgaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vdmFsZW50aW5pdG5lbGF2L2M3NTk4ZmNmYzhlNTM2NThmNjZmZWVhOWQzYmFmYjQwIGZvciBpbnN0cnVjdGlvbnMKCmBgYHtyIHNldHVwIHdvcmxkIG1hcHN9CmxpYnJhcnkoZ2dzcGF0aWFsKQoKICB3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQoKIyB+fn5+fn5+fn5+fiBEb3dubG9hZCBzaGFwZWZpbGUgZnJvbSB3d3cubmF0dXJhbGVhcnRoZGF0YS5jb20gfn5+fn5+fn5+fn4gIwojIERvd25sb2FkIGNvdW50cmllcyBkYXRhCmRvd25sb2FkLmZpbGUodXJsID0gImh0dHA6Ly93d3cubmF0dXJhbGVhcnRoZGF0YS5jb20vaHR0cC8vd3d3Lm5hdHVyYWxlYXJ0aGRhdGEuY29tL2Rvd25sb2FkLzExMG0vY3VsdHVyYWwvbmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcy56aXAiLCAKICAgICAgICAgICAgICBkZXN0ZmlsZSA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIpCiMgdW56aXAgdGhlIHNoYXBlZmlsZSBpbiB0aGUgZGlyZWN0b3J5IG1lbnRpb25lZCB3aXRoICJleGRpciIgYXJndW1lbnQKdW56aXAoemlwZmlsZT0ibmVfMTEwbV9hZG1pbl8wX2NvdW50cmllcy56aXAiLCBleGRpciA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzIikKIyBkZWxldGUgdGhlIHppcCBmaWxlCmZpbGUucmVtb3ZlKCJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzLnppcCIpCiMgcmVhZCB0aGUgc2hhcGVmaWxlIHdpdGggcmVhZE9HUiBmcm9tIHJnZGFsIHBhY2thZ2UKTkVfY291bnRyaWVzIDwtIHJlYWRPR1IoZHNuID0gIm5lXzExMG1fYWRtaW5fMF9jb3VudHJpZXMiLCBsYXllciA9ICJuZV8xMTBtX2FkbWluXzBfY291bnRyaWVzIikKY2xhc3MoTkVfY291bnRyaWVzKSAjIGlzIGEgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIG9iamVjdAoKIyB+fn5+fn5+fn5+fiBTcGxpdCB3b3JsZCBtYXAgYnkgInNwbGl0IGxpbmUiIH5+fn5+fn5+fn5+ICMKCiMgc2hpZnQgY2VudHJhbC9wcmltZSBtZXJpZGlhbiB0b3dhcmRzIHdlc3Qg4oCTIHBvc2l0aXZlIHZhbHVlcyBvbmx5CnNoaWZ0IDwtIDE4MCArMzAKCiMgY3JlYXRlICJzcGxpdCBsaW5lIiB0byBzcGxpdCBjb3VudHJ5IHBvbHlnb25zCldHUzg0IDwtIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK25vX2RlZnMgK2VsbHBzPVdHUzg0ICt0b3dnczg0PTAsMCwwIikKc3BsaXQubGluZSA8LSBTcGF0aWFsTGluZXMobGlzdChMaW5lcyhsaXN0KExpbmUoY2JpbmQoMTgwLXNoaWZ0LGMoLTkwLDkwKSkpKSwgSUQ9ImxpbmUiKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHByb2o0c3RyaW5nPVdHUzg0KQoKIyBOT1RFIC0gaW4gY2FzZSBvZiBUb3BvbG9neUV4Y2VwdGlvbicgZXJyb3JzIHdoZW4gaW50ZXJzZWN0aW5nIGxpbmUgd2l0aCBjb3VudHJ5IHBvbHlnb25zLAojIGFwcGx5IHRoZSBnQnVmZmVyIHNvbHV0aW9uIHN1Z2dlc3RlZCBhdDoKIyBodHRwOi8vZ2lzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8xNjM0NDUvci1zb2x1dGlvbi1mb3ItdG9wb2xvZ3lleGNlcHRpb24taW5wdXQtZ2VvbS0xLWlzLWludmFsaWQtc2VsZi1pbnRlcnNlY3Rpb24tZXIKTkVfY291bnRyaWVzIDwtIGdCdWZmZXIoTkVfY291bnRyaWVzLCBieWlkPVRSVUUsIHdpZHRoPTApCgojIGludGVyc2VjdGluZyBsaW5lIHdpdGggY291bnRyeSBwb2x5Z29ucwpsaW5lLmdJbnQgPC0gZ0ludGVyc2VjdGlvbihzcGxpdC5saW5lLCBORV9jb3VudHJpZXMpCgojIGNyZWF0ZSBhIHZlcnkgdGhpbiBwb2x5Z29uIChidWZmZXIpIG91dCBvZiB0aGUgaW50ZXJzZWN0aW5nICJzcGxpdCBsaW5lIgpiZiA8LSBnQnVmZmVyKGxpbmUuZ0ludCwgYnlpZD1UUlVFLCB3aWR0aD0wLjAwMDAwMSkgIAoKIyBzcGxpdCBjb3VudHJ5IHBvbHlnb25zIHVzaW5nIGludGVyc2VjdGluZyB0aGluIHBvbHlnb24gKGJ1ZmZlcikKTkVfY291bnRyaWVzLnNwbGl0IDwtIGdEaWZmZXJlbmNlKE5FX2NvdW50cmllcywgYmYsIGJ5aWQ9VFJVRSkKIyBwbG90KE5FX2NvdW50cmllcy5zcGxpdCkgIyBjaGVjayBtYXAKY2xhc3MoTkVfY291bnRyaWVzLnNwbGl0KSAjIGlzIGEgU3BhdGlhbFBvbHlnb25zIG9iamVjdAoKIyB+fn5+fn5+fn5+fiBDcmVhdGUgZ3JhdGljdWxlcyB+fn5+fn5+fn5+fiAjCiMgY3JlYXRlIGEgYm91bmRpbmcgYm94IC0gd29ybGQgZXh0ZW50CmIuYm94IDwtIGFzKHJhc3Rlcjo6ZXh0ZW50KC0xODAsIDE4MCwgLTkwLCA5MCksICJTcGF0aWFsUG9seWdvbnMiKQojIGFzc2lnbiBDUlMgdG8gYm94CnByb2o0c3RyaW5nKGIuYm94KSA8LSBXR1M4NAojIGNyZWF0ZSBncmF0aWN1bGVzL2dyaWQgbGluZXMgZnJvbSBib3gKZ3JpZCA8LSBncmlkbGluZXMoYi5ib3gsIAogICAgICAgICAgICAgICAgICBlYXN0cyAgPSBzZXEoZnJvbT0tMTgwLCB0bz0xODAsIGJ5PTIwKSwKICAgICAgICAgICAgICAgICAgbm9ydGhzID0gc2VxKGZyb209LTkwLCB0bz05MCwgYnk9MTApKQoKIyBjcmVhdGUgbGFiZWxzIGZvciBncmF0aWN1bGVzCmdyaWQubGJsIDwtIGxhYmVscyhncmlkLCBzaWRlID0gMTo0KQoKIyB0cmFuc2Zvcm0gbGFiZWxzIGZyb20gU3BhdGlhbFBvaW50c0RhdGFGcmFtZSB0byBhIGRhdGEgdGFibGUgdGhhdCBnZ3Bsb3QgY2FuIHVzZQpncmlkLmxibC5EVCA8LSBkYXRhLnRhYmxlKGdyaWQubGJsQGNvb3JkcywgZ3JpZC5sYmxAZGF0YSkKCiMgcHJlcGFyZSBsYWJlbHMgd2l0aCByZWd1bGFyIGV4cHJlc3Npb246CiMgLSBkZWxldGUgdW53YW50ZWQgbGFiZWxzCmdyaWQubGJsLkRUWywgbGFiZWxzIDo9IGdzdWIocGF0dGVybj0iMTgwXFwqZGVncmVlfDkwXFwqZGVncmVlXFwqTnw5MFxcKmRlZ3JlZVxcKlMiLCByZXBsYWNlbWVudD0iIiwgeD1sYWJlbHMpXQojIC0gcmVwbGFjZSBwYXR0ZXJuICIqZGVncmVlIiB3aXRoICLCsCIgKCogbmVlZHMgdG8gYmUgZXNjYXBlZCB3aXRoIFxcKQpncmlkLmxibC5EVFssIGxibCA6PSBnc3ViKHBhdHRlcm49IlxcKmRlZ3JlZSIsIHJlcGxhY2VtZW50PSLCsCIsIHg9bGFiZWxzKV0KIyAtIGRlbGV0ZSBhbnkgcmVtYWluaW5nICIqIgpncmlkLmxibC5EVFssIGxibCA6PSBnc3ViKHBhdHRlcm49IipcXCoiLCByZXBsYWNlbWVudD0iIiwgeD1sYmwpXQoKIyBhZGp1c3QgY29vcmRpbmF0ZXMgb2YgbGFiZWxzIHNvIHRoYXQgdGhleSBmaXQgaW5zaWRlIHRoZSBnbG9iZQpncmlkLmxibC5EVFssIGxvbmcgOj0gaWZlbHNlKGNvb3Jkcy54MSAlaW4lIGMoLTE4MCwxODApLCBjb29yZHMueDEqMTc1LzE4MCwgY29vcmRzLngxKV0KZ3JpZC5sYmwuRFRbLCBsYXQgIDo9IGlmZWxzZShjb29yZHMueDIgJWluJSBjKC05MCw5MCksIGNvb3Jkcy54Mio4Mi85MCwgY29vcmRzLngyKV0KCiMgfn5+fn5+fn5+fn4gUHJlcGFyZSBkYXRhIGZvciBnZ3Bsb3QsIHNoaWZ0ICYgcHJvamVjdCBjb29yZGluYXRlcyB+fn5+fn5+fn5+fiAjCiMgZ2l2ZSB0aGUgUE9SSi40IHN0cmluZyBmb3IgRWNrZXJ0IElWIHByb2plY3Rpb24gKCBjaGFuZ2VkIHRvIGRpZmZlcmVudCBwcm9qZWN0aW9uLCAiK3Byb2o9ZWNrNCArbG9uXzA9MCAreF8wPTAgK3lfMD0wICtlbGxwcz1XR1M4NCArZGF0dW09V0dTODQgK3VuaXRzPW0gK25vX2RlZnMiIGZvciBlY2tlcnQpClBST0ogPC0gIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0ICtub19kZWZzICtlbGxwcz1XR1M4NCArdG93Z3M4ND0wLDAsMCIgCgojIHRyYW5zZm9ybSBncmF0aWN1bGVzIGZyb20gU3BhdGlhbExpbmVzIHRvIGEgZGF0YSB0YWJsZSB0aGF0IGdncGxvdCBjYW4gdXNlCmdyaWQuRFQgPC0gZGF0YS50YWJsZShtYXBfZGF0YShTcGF0aWFsTGluZXNEYXRhRnJhbWUoc2w9Z3JpZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1kYXRhLmZyYW1lKDE6bGVuZ3RoKGdyaWQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2guSUQgPSBGQUxTRSkpKQojIHByb2plY3QgY29vcmRpbmF0ZXMKIyBhc3NpZ24gbWF0cml4IG9mIHByb2plY3RlZCBjb29yZGluYXRlcyBhcyB0d28gY29sdW1ucyBpbiBkYXRhIHRhYmxlCmdyaWQuRFRbLCBjKCJYIiwiWSIpIDo9IGRhdGEudGFibGUocHJvamVjdChjYmluZChsb25nLCBsYXQpLCBwcm9qPVBST0opKV0KCiMgcHJvamVjdCBjb29yZGluYXRlcyBvZiBsYWJlbHMKZ3JpZC5sYmwuRFRbLCBjKCJYIiwiWSIpIDo9IGRhdGEudGFibGUocHJvamVjdChjYmluZChsb25nLCBsYXQpLCBwcm9qPVBST0opKV0KCiMgdHJhbnNmb3JtIHNwbGl0IGNvdW50cnkgcG9seWdvbnMgaW4gYSBkYXRhIHRhYmxlIHRoYXQgZ2dwbG90IGNhbiB1c2UKQ291bnRyeS5EVF9zaGlmdCA8LSBkYXRhLnRhYmxlKG1hcF9kYXRhKGFzKE5FX2NvdW50cmllcy5zcGxpdCwgIlNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSIpKSkKQ291bnRyeS5EVCA8LSBkYXRhLnRhYmxlKG1hcF9kYXRhKGFzKE5FX2NvdW50cmllcywgIlNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZSIpKSkKIyBTaGlmdCBjb29yZGluYXRlcwpDb3VudHJ5LkRUX3NoaWZ0WywgbG9uZy5uZXcgOj0gbG9uZyArIHNoaWZ0XQpDb3VudHJ5LkRUX3NoaWZ0WywgbG9uZy5uZXcgOj0gaWZlbHNlKGxvbmcubmV3ID4gMTgwLCBsb25nLm5ldy0zNjAsIGxvbmcubmV3KV0KCiMgcHJvamVjdCBjb29yZGluYXRlcyAKQ291bnRyeS5EVFssIGMoIlgiLCJZIikgOj0gZGF0YS50YWJsZShwcm9qZWN0KGNiaW5kKGxvbmcsIGxhdCksIHByb2o9UFJPSikpXQpDb3VudHJ5LkRUX3NoaWZ0WywgYygiWCIsIlkiKSA6PSBkYXRhLnRhYmxlKHByb2plY3QoY2JpbmQobG9uZy5uZXcsIGxhdCksIHByb2o9UFJPSikpXQoKIyB+fn5+fn5+fn5+fiBQbG90IG1hcCB+fn5+fn5+fn5+fiAjCmdncGxvdCgpICsgCiAgICAjIGFkZCBwcm9qZWN0ZWQgY291bnRyaWVzCiAgICBnZW9tX3BvbHlnb24oZGF0YSA9IENvdW50cnkuRFRfc2hpZnQsIAogICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZy5uZXcrMTUwLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImdyYXk3MCIsIAogICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUpICsKICAgICMgYWRkIGdyYXRpY3VsZXMKICAgIGdlb21fcGF0aChkYXRhID0gZ3JpZC5EVCwgCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgIGxpbmV0eXBlID0gImRvdHRlZCIsIGNvbG91ciA9ICJncmV5NTAiLCBzaXplID0gLjI1KSArCiAgICAjIGFkZCBhIGJvdW5kaW5nIGJveCAoc2VsZWN0IGdyYXRpY3VsZXMgYXQgZWRnZXMpCiAgICBnZW9tX3BhdGgoZGF0YSA9IGdyaWQuRFRbKGxvbmcgJWluJSBjKC0xODAsMTgwKSAmIHJlZ2lvbiA9PSAiTlMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwobG9uZyAlaW4lIGMoLTE4MCwxODApICYgbGF0ICVpbiUgYygtOTAsOTApICYgcmVnaW9uID09ICJFVyIpXSwgCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgZ3JvdXAgPSBncm91cCksIAogICAgICAgICAgICAgIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IC4zKSArCiAgICAjIGFkZCBncmF0aWN1bGUgbGFiZWxzCiAgICBnZW9tX3RleHQoZGF0YSA9IGdyaWQubGJsLkRULCAjIGxhdGl0dWRlCiAgICAgICAgICAgICAgYWVzKHggPSBYLCB5ID0gWSwgbGFiZWwgPSBsYmwpLCAKICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTUwIiwgc2l6ZSA9IDIpICsKICAgICMgZW5zdXJlcyB0aGF0IG9uZSB1bml0IG9uIHRoZSB4LWF4aXMgaXMgdGhlIHNhbWUgbGVuZ3RoIGFzIG9uZSB1bml0IG9uIHRoZSB5LWF4aXMKICAgIGNvb3JkX2VxdWFsKCkgKyAjIHNhbWUgYXMgY29vcmRfZml4ZWQocmF0aW8gPSAxKQogICAgIyBzZXQgZW1wdHkgdGhlbWUKICAgIHRoZW1lX3ZvaWQoKQoKYGBgCgpgYGB7ciBtYXBwaW5nIGVhY2ggcmVnaW9ufQoKcmVnaW9uX21hcHMgPC0gbGlzdCgpCnJlZ2lvbnNfc2hpZnRfcHJvamVjdGlvbiA8LSBjKCJ3ZXN0X3BhY19zcGRmX3NoaWZ0IiwgImVhc3RfcGFjX3NwZGZfc2hpZnQiKQoKCgpmb3IgKGkgaW4gMTpsZW5ndGgocmVnaW9uX25hbWVzKSkgewogIAogIHJlZ2lvbl9zcGRmIDwtIGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hc2siKSkKICAKICBpZihyZWdpb25fbmFtZXNbaV0gJWluJSByZWdpb25zX3NoaWZ0X3Byb2plY3Rpb24pIHsKICAKICAjcGFjaWZpYyBjZW50ZXJlZCBwcm9qZWN0aW9uCiAgCiAgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnQgPC0gZXh0ZW50KGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCJfbWFza18xcyIpKSkgIyB0YWtlIGV4dGVudCBvZiByZWdpb24KICAKICAjY29udmVydCByYXN0ZXJzIHRvIGRmcyBkYXRhIGZyYW1lCiAgcmVnaW9uX3NwZGYgPC0gYXMoZ2V0KHBhc3RlMChyZWdpb25fbmFtZXNbaV0sIl9tYXNrXzFzIikpLCAiU3BhdGlhbFBpeGVsc0RhdGFGcmFtZSIpCiAgcmVnaW9uX2RmIDwtIGFzLmRhdGEuZnJhbWUocmVnaW9uX3NwZGYpCiAgY29sbmFtZXMocmVnaW9uX2RmKSA8LSBjKCJ2YWx1ZSIsICJ4IiwgInkiKQogIAogIAogIChyZWdpb25fbWFwc1tbaV1dIDwtIGdncGxvdCgpICsgCiAgICAjIGFkZCBwcm9qZWN0ZWQgY291bnRyaWVzCiAgICBnZW9tX3BvbHlnb24oZGF0YSA9IENvdW50cnkuRFRfc2hpZnQsIAogICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZy5uZXcrMTUwLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgCiAgICAgICAgICAgICAgICAgY29sb3VyID0gImdyYXk3MCIsIAogICAgICAgICAgICAgICAgIGZpbGwgPSAiZ3JheTkwIiwgCiAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUpICsKICAgIGdlb21fdGlsZShkYXRhID0gcmVnaW9uX2RmLCBhZXMoeCA9IHgsIHkgPSB5LCBmaWxsID0gdmFsdWUpLCBjb2xvciA9ICJzZWFncmVlbjQiKSArCiAgICBjb29yZF9zZih4ID0gYyhyZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFsxXSwgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbMl0pLCB5ID0gYyhyZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFszXSwgcmVnaW9uX3NwZGZfbWFza18xc19leHRlbnRbNF0pKSArCiAgICBsYWJzKCB4ID0gZXhwcmVzc2lvbigiTG9uZ2l0dWRlICgiKn5kZWdyZWUqRSoiKSIpLCB5ID0gZXhwcmVzc2lvbigiTGF0aXR1ZGUgKCIqfmRlZ3JlZSpOKiIpIikpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMCkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCiAgCiAgZmlsZW5hbWUgPC0gcGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwgIl9tYXAuanBnIikKICBnZ3NhdmUocGxvdCA9IHJlZ2lvbl9tYXBzW1tpXV0sIGZpbGVuYW1lID0gZmlsZW5hbWUsIGhlaWdodCA9IDQsIHVuaXRzID0gYygiaW4iKSkKICAKICB9IGVsc2UgewoKICAjYXRsYW50aWMgY2VudGVyZWQgcHJvamVjdGlvbgogIHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50IDwtIGV4dGVudChnZXQocGFzdGUwKHJlZ2lvbl9uYW1lc1tpXSwiX21hc2tfMXMiKSkpICMgdGFrZSBleHRlbnQgb2YgcmVnaW9uCiAgCiAgI2NvbnZlcnQgcmFzdGVycyB0byBkZnMgZGF0YSBmcmFtZQogIHJlZ2lvbl9zcGRmIDwtIGFzKGdldChwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCJfbWFza18xcyIpKSwgIlNwYXRpYWxQaXhlbHNEYXRhRnJhbWUiKQogIHJlZ2lvbl9kZiA8LSBhcy5kYXRhLmZyYW1lKHJlZ2lvbl9zcGRmKQogIGNvbG5hbWVzKHJlZ2lvbl9kZikgPC0gYygidmFsdWUiLCAieCIsICJ5IikKICAKICAKICAocmVnaW9uX21hcHNbW2ldXSA8LSBnZ3Bsb3QoKSArIAogICAgIyBhZGQgcHJvamVjdGVkIGNvdW50cmllcwogICAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBDb3VudHJ5LkRULCAKICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApLCAKICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JheTcwIiwgCiAgICAgICAgICAgICAgICAgZmlsbCA9ICJncmF5OTAiLCAKICAgICAgICAgICAgICAgICBzaXplID0gMC4yNSkgKwogICAgZ2VvbV90aWxlKGRhdGEgPSByZWdpb25fZGYsIGFlcyh4ID0geCwgeSA9IHksIGZpbGwgPSB2YWx1ZSksIGNvbG9yID0gInNlYWdyZWVuNCIpICsKICAgIGNvb3JkX3NmKHggPSBjKHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzFdLCByZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFsyXSksIHkgPSBjKHJlZ2lvbl9zcGRmX21hc2tfMXNfZXh0ZW50WzNdLCByZWdpb25fc3BkZl9tYXNrXzFzX2V4dGVudFs0XSkpICsKICAgIGxhYnMoIHggPSBleHByZXNzaW9uKCJMb25naXR1ZGUgKCIqfmRlZ3JlZSpFKiIpIiksIHkgPSBleHByZXNzaW9uKCJMYXRpdHVkZSAoIip+ZGVncmVlKk4qIikiKSkgKwogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAwKSArCiAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKICAKICBmaWxlbmFtZSA8LSBwYXN0ZTAocmVnaW9uX25hbWVzW2ldLCAiX21hcC5qcGciKQogIGdnc2F2ZShwbG90ID0gcmVnaW9uX21hcHNbW2ldXSwgZmlsZW5hbWUgPSBmaWxlbmFtZSwgaGVpZ2h0ID0gNCwgdW5pdHMgPSBjKCJpbiIpKQogIAogIH0KICAKICB9CmBgYAoKQ29tYmluaW5nIHBsb3RzCgpyZWdpb25fbWFwczogCiJ3ZXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJlYXN0X3BhY19zcGRmX3NoaWZ0IiwgCiJ3ZXN0X2F0bF9zcGRmIiwgCiJ3ZXN0X2luZF9zcGRmIiwgCiJlYXN0X2F0bF9zcGRmX25vYnVmIiwgCiJlYXN0X2luZF9zcGRmIgoKUGxvdHMgb2YgYXJlYSB2ZXJzdXMgbGF0aXR1ZGUKYXJlYV9sYXRpdHVkZV9lYXN0X3BhYwoKTm93LCBjb21iaW5lIHBsb3RzCgpgYGB7ciBjb21iaW5pbmcgcGxvdHN9CmxpYnJhcnkoZWdnKQpsaWJyYXJ5KGdncHVicikKCiN3ZXN0IHBhY2lmaWMKKHdlc3RfcGFjaWZpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbMV1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9wYWMgCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKSwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gd2VzdF9wYWNpZmljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJ3ZXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBwYWNpZmljCihlYXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzJdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX2Vhc3RfcGFjIAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICkKICAgICAgICAgICwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gZWFzdF9wYWNpZmljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJlYXN0X3BhY2lmaWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgoKI3dlc3QgYXRsYW50aWMKKHdlc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QgPC0gZWdnOjpnZ2FycmFuZ2UocmVnaW9uX21hcHNbWzNdXSwgCiAgICAgICAgICBhcmVhX2xhdGl0dWRlX3dlc3RfYXRsCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKQogICAgICAgICAgLCAKCiAgICAgICAgICBucm93ID0gMSwKICAgICAgICAgIHRvcCA9IFQpKQoKZ2dzYXZlKHBsb3QgPSB3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90LCBmaWxlbmFtZSA9ICJ3ZXN0X2F0bGFudGljX21lcmdlX21hcF9wbG90LmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQoKI3dlc3QgaW5kaWFuCih3ZXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNF1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfd2VzdF9pbmQgCiAgICAgICAgICArIAogICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkgKQogICAgICAgICAgLCAKCiAgICAgICAgICBucm93ID0gMSwKICAgICAgICAgIHRvcCA9IFQpKQoKZ2dzYXZlKHBsb3QgPSB3ZXN0X2luZGlhbl9tZXJnZV9tYXBfcGxvdCwgZmlsZW5hbWUgPSAid2VzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBhdGxhbnRpYwooZWFzdF9hdGxhbnRpY19tZXJnZV9tYXBfcGxvdCA8LSBlZ2c6OmdnYXJyYW5nZShyZWdpb25fbWFwc1tbNV1dLCAKICAgICAgICAgIGFyZWFfbGF0aXR1ZGVfZWFzdF9hdGwKICAgICAgICAgICsgCiAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSApCiAgICAgICAgICAsIAoKICAgICAgICAgIG5yb3cgPSAxLAogICAgICAgICAgdG9wID0gVCkpCgpnZ3NhdmUocGxvdCA9IGVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gImVhc3RfYXRsYW50aWNfbWVyZ2VfbWFwX3Bsb3QuanBnIiwgd2lkdGggPSA3LCBoZWlnaHQgPSAzLCB1bml0cyA9ICJpbiIpCgojZWFzdCBpbmRpYW4KKGVhc3RfaW5kaWFuX21lcmdlX21hcF9wbG90IDwtIGVnZzo6Z2dhcnJhbmdlKHJlZ2lvbl9tYXBzW1s2XV0sIAogICAgICAgICAgYXJlYV9sYXRpdHVkZV9lYXN0X2luZAogICAgICAgICAgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpICkKICAgICAgICAgICwgCgogICAgICAgICAgbnJvdyA9IDEsCiAgICAgICAgICB0b3AgPSBUKSkKCmdnc2F2ZShwbG90ID0gZWFzdF9pbmRpYW5fbWVyZ2VfbWFwX3Bsb3QsIGZpbGVuYW1lID0gImVhc3RfaW5kaWFuX21lcmdlX21hcF9wbG90LmpwZyIsIHdpZHRoID0gNywgaGVpZ2h0ID0gMywgdW5pdHMgPSAiaW4iKQpgYGAKCgpNYWtlIG1hcCBvZiB3b3JsZAoKRWFjaCByZWdpb24gY29kZWQgd2l0aCAjIGV4cGFuc2lvbnMgYW5kICMgY29udHJhY3Rpb25zCgpgYGB7cn0KCnNhdmUoc2lnbmlmaWNhbnRfY2hhbmdlcy5sb25nLCBzaWduaWZpY2FudF9jaGFuZ2VzLCBmaWxlID0gInNpZ25pZmljYW50X2NoYW5nZXMuUkRhdGEiKQoKYGBgCgo=